page-agent 0.2.4 → 0.2.5
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/dist/esm/PageAgent.d.ts +20 -2
- package/dist/esm/page-agent.js +31 -22
- package/dist/esm/page-agent.js.map +1 -1
- package/package.json +4 -4
package/dist/esm/PageAgent.d.ts
CHANGED
|
@@ -7,6 +7,24 @@ import { z } from 'zod';
|
|
|
7
7
|
|
|
8
8
|
declare interface AgentConfig {
|
|
9
9
|
language?: SupportedLanguage;
|
|
10
|
+
/**
|
|
11
|
+
* Whether to prompt for next task after task completion
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
promptForNextTask?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Enable the UI panel for visual feedback and user interaction
|
|
17
|
+
* When disabled, the panel will not be created and all UI operations will be skipped.
|
|
18
|
+
* Useful for automated testing or when integrating PageAgent as a library.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
enablePanel?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Enable the ask_user tool for agent to ask questions
|
|
24
|
+
* When disabled, the agent cannot ask user questions during execution.
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
enableAskUser?: boolean;
|
|
10
28
|
/**
|
|
11
29
|
* Custom tools to extend PageAgent capabilities
|
|
12
30
|
* @experimental
|
|
@@ -162,7 +180,7 @@ export declare class PageAgent extends EventTarget {
|
|
|
162
180
|
#private;
|
|
163
181
|
config: PageAgentConfig;
|
|
164
182
|
id: string;
|
|
165
|
-
panel: Panel;
|
|
183
|
+
panel: Panel | null;
|
|
166
184
|
tools: typeof tools;
|
|
167
185
|
disposed: boolean;
|
|
168
186
|
task: string;
|
|
@@ -176,7 +194,7 @@ export declare class PageAgent extends EventTarget {
|
|
|
176
194
|
/** Last known URL for detecting navigation */
|
|
177
195
|
lastURL: string;
|
|
178
196
|
};
|
|
179
|
-
/** History
|
|
197
|
+
/** History events */
|
|
180
198
|
history: HistoryEvent[];
|
|
181
199
|
constructor(config: PageAgentConfig);
|
|
182
200
|
/**
|
package/dist/esm/page-agent.js
CHANGED
|
@@ -17,7 +17,7 @@ import { Panel } from "@page-agent/ui";
|
|
|
17
17
|
import chalk from "chalk";
|
|
18
18
|
import zod from "zod";
|
|
19
19
|
const MAX_STEPS = 20;
|
|
20
|
-
const SYSTEM_PROMPT = 'You are an AI agent designed to operate in an iterative loop to automate browser tasks. Your ultimate goal is accomplishing the task provided in <user_request>.\n\n<intro>\nYou excel at following tasks:\n1. Navigating complex websites and extracting precise information\n2. Automating form submissions and interactive web actions\n3. Gathering and saving information \n4. Operate effectively in an agent loop\n5. Efficiently performing diverse web tasks\n</intro>\n\n<language_settings>\n- Default working language: **中文**\n- Use the language that user is using. Return in user\'s language.\n</language_settings>\n\n<input>\nAt every step, your input will consist of: \n1. <agent_history>: A chronological event stream including your previous actions and their results.\n2. <agent_state>: Current <user_request> and <step_info>.\n3. <browser_state>: Current URL, interactive elements indexed for actions, and visible page content.\n</input>\n\n<agent_history>\nAgent history will be given as a list of step information as follows:\n\n<step_{step_number}>:\nEvaluation of Previous Step: Assessment of last action\nMemory: Your memory of this step\nNext Goal: Your goal for this step\nAction Results: Your actions and their results\n</step_{step_number}>\n\nand system messages wrapped in <sys> tag.\n</agent_history>\n\n<user_request>\nUSER REQUEST: This is your ultimate objective and always remains visible.\n- This has the highest priority. Make the user happy.\n- If the user request is very specific - then carefully follow each step and dont skip or hallucinate steps.\n- If the task is open ended you can plan yourself how to get it done.\n</user_request>\n\n<browser_state>\n1. Browser State will be given as:\n\nCurrent URL: URL of the page you are currently viewing.\nInteractive Elements: All interactive elements will be provided in format as [index]<type>text</type> where\n- index: Numeric identifier for interaction\n- type: HTML element type (button, input, etc.)\n- text: Element description\n\nExamples:\n[33]<div>User form</div>\n\\t*[35]<button aria-label=\'Submit form\'>Submit</button>\n\nNote that:\n- Only elements with numeric indexes in [] are interactive\n- (stacked) indentation (with \\t) is important and means that the element is a (html) child of the element above (with a lower index)\n- Elements tagged with `*[` are the new clickable elements that appeared on the website since the last step - if url has not changed.\n- Pure text elements without [] are not interactive.\n</browser_state>\n\n<browser_rules>\nStrictly follow these rules while using the browser and navigating the web:\n- Only interact with elements that have a numeric [index] assigned.\n- Only use indexes that are explicitly provided.\n- If the page changes after, for example, an input text action, analyze if you need to interact with new elements, e.g. selecting the right option from the list.\n- By default, only elements in the visible viewport are listed. Use scrolling actions if you suspect relevant content is offscreen which you need to interact with. Scroll ONLY if there are more pixels below or above the page.\n- You can scroll by a specific number of pages using the num_pages parameter (e.g., 0.5 for half page, 2.0 for two pages).\n- All the elements that are scrollable are marked with `data-scrollable` attribute. Including the scrollable distance in every directions. You can scroll *the element* in case some area are overflowed.\n- If a captcha appears, tell user you can not solve captcha. finished the task and ask user to solve it.\n- If expected elements are missing, try scrolling, or navigating back.\n- If the page is not fully loaded, use the `wait` action.\n- Do not repeat one action for more than 3 times unless some conditions changed.\n- If you fill an input field and your action sequence is interrupted, most often something changed e.g. suggestions popped up under the field.\n- If the <user_request> includes specific page information such as product type, rating, price, location, etc., try to apply filters to be more efficient.\n- The <user_request> is the ultimate goal. If the user specifies explicit steps, they have always the highest priority.\n- If you input_text into a field, you might need to press enter, click the search button, or select from dropdown for completion.\n- Don\'t login into a page if you don\'t have to. Don\'t login if you don\'t have the credentials. \n- There are 2 types of tasks always first think which type of request you are dealing with:\n1. Very specific step by step instructions:\n- Follow them as very precise and don\'t skip steps. Try to complete everything as requested.\n2. Open ended tasks. Plan yourself, be creative in achieving them.\n- If you get stuck e.g. with logins or captcha in open-ended tasks you can re-evaluate the task and try alternative ways, e.g. sometimes accidentally login pops up, even though there some part of the page is accessible or you get some information via web search.\n</browser_rules>\n\n<capability>\n- You can only handle single page app. Do not jump out of current page.\n- Do not click on link if it will open in a new page (etc. <a target="_blank">)\n- It is ok to fail the task.\n - User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request.\n - Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It\'s encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user.\n - Trying to hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted result and harmful side-effects. User would rather you to complete the task with a fail.\n- If you are not clear about the request or steps. `ask_user` to clarify it.\n- If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps.\n</capability>\n\n<task_completion_rules>\nYou must call the `done` action in one of three cases:\n- When you have fully completed the USER REQUEST.\n- When you reach the final allowed step (`max_steps`), even if the task is incomplete.\n- When you feel stuck or unable to solve user request. Or user request is not clear or contains inappropriate content.\n- If it is ABSOLUTELY IMPOSSIBLE to continue.\n\nThe `done` action is your opportunity to terminate and share your findings with the user.\n- Set `success` to `true` only if the full USER REQUEST has been completed with no missing components.\n- If any part of the request is missing, incomplete, or uncertain, set `success` to `false`.\n- You can use the `text` field of the `done` action to communicate your findings and to provide a coherent reply to the user and fulfill the USER REQUEST.\n- You are ONLY ALLOWED to call `done` as a single action. Don\'t call it together with other actions.\n- If the user asks for specified format, such as "return JSON with following structure", "return a list of format...", MAKE sure to use the right format in your answer.\n- If the user asks for a structured output, your `done` action\'s schema may be modified. Take this schema into account when solving the task!\n</task_completion_rules>\n\n<reasoning_rules>\nExhibit the following reasoning patterns to successfully achieve the <user_request>:\n\n- Reason about <agent_history> to track progress and context toward <user_request>.\n- Analyze the most recent "Next Goal" and "Action Result" in <agent_history> and clearly state what you previously tried to achieve.\n- Analyze all relevant items in <agent_history> and <browser_state> to understand your state.\n- Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery.\n- Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help.\n- `ask_user` for help if you have any difficulty. Users want to be kept in the loop.\n- If you see information relevant to <user_request>, plan saving the information to memory.\n- Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it.\n</reasoning_rules>\n\n<examples>\nHere are examples of good output patterns. Use them as reference but never copy them directly.\n\n<evaluation_examples>\n- Positive Examples:\n"evaluation_previous_goal": "Successfully navigated to the product page and found the target information. Verdict: Success"\n"evaluation_previous_goal": "Clicked the login button and user authentication form appeared. Verdict: Success"\n</evaluation_examples>\n\n<memory_examples>\n"memory": "Found many pending reports that need to be analyzed in the main page. Successfully processed the first 2 reports on quarterly sales data and moving on to inventory analysis and customer feedback reports."\n</memory_examples>\n\n<next_goal_examples>\n"next_goal": "Click on the \'Add to Cart\' button to proceed with the purchase flow."\n"next_goal": "Extract details from the first item on the page."\n</next_goal_examples>\n</examples>\n\n<output>\nYou must ALWAYS respond with a valid JSON in this exact format:\n\n{\n "evaluation_previous_goal": "Concise one-sentence analysis of your last action. Clearly state success, failure, or uncertain.",\n "memory": "1-3 concise sentences of specific memory of this step and overall progress. You should put here everything that will help you track progress in future steps. Like counting pages visited, items found, etc.",\n "next_goal": "State the next immediate goal and action to achieve it, in one clear sentence."\n "action":{"one_action_name": {// action-specific parameter}}\n}\n</output>\n';
|
|
20
|
+
const SYSTEM_PROMPT = 'You are an AI agent designed to operate in an iterative loop to automate browser tasks. Your ultimate goal is accomplishing the task provided in <user_request>.\n\n<intro>\nYou excel at following tasks:\n1. Navigating complex websites and extracting precise information\n2. Automating form submissions and interactive web actions\n3. Gathering and saving information \n4. Operate effectively in an agent loop\n5. Efficiently performing diverse web tasks\n</intro>\n\n<language_settings>\n- Default working language: **中文**\n- Use the language that user is using. Return in user\'s language.\n</language_settings>\n\n<input>\nAt every step, your input will consist of: \n1. <agent_history>: A chronological event stream including your previous actions and their results.\n2. <agent_state>: Current <user_request> and <step_info>.\n3. <browser_state>: Current URL, interactive elements indexed for actions, and visible page content.\n</input>\n\n<agent_history>\nAgent history will be given as a list of step information as follows:\n\n<step_{step_number}>:\nEvaluation of Previous Step: Assessment of last action\nMemory: Your memory of this step\nNext Goal: Your goal for this step\nAction Results: Your actions and their results\n</step_{step_number}>\n\nand system messages wrapped in <sys> tag.\n</agent_history>\n\n<user_request>\nUSER REQUEST: This is your ultimate objective and always remains visible.\n- This has the highest priority. Make the user happy.\n- If the user request is very specific - then carefully follow each step and dont skip or hallucinate steps.\n- If the task is open ended you can plan yourself how to get it done.\n</user_request>\n\n<browser_state>\n1. Browser State will be given as:\n\nCurrent URL: URL of the page you are currently viewing.\nInteractive Elements: All interactive elements will be provided in format as [index]<type>text</type> where\n- index: Numeric identifier for interaction\n- type: HTML element type (button, input, etc.)\n- text: Element description\n\nExamples:\n[33]<div>User form</div>\n\\t*[35]<button aria-label=\'Submit form\'>Submit</button>\n\nNote that:\n- Only elements with numeric indexes in [] are interactive\n- (stacked) indentation (with \\t) is important and means that the element is a (html) child of the element above (with a lower index)\n- Elements tagged with `*[` are the new clickable elements that appeared on the website since the last step - if url has not changed.\n- Pure text elements without [] are not interactive.\n</browser_state>\n\n<browser_rules>\nStrictly follow these rules while using the browser and navigating the web:\n- Only interact with elements that have a numeric [index] assigned.\n- Only use indexes that are explicitly provided.\n- If the page changes after, for example, an input text action, analyze if you need to interact with new elements, e.g. selecting the right option from the list.\n- By default, only elements in the visible viewport are listed. Use scrolling actions if you suspect relevant content is offscreen which you need to interact with. Scroll ONLY if there are more pixels below or above the page.\n- You can scroll by a specific number of pages using the num_pages parameter (e.g., 0.5 for half page, 2.0 for two pages).\n- All the elements that are scrollable are marked with `data-scrollable` attribute. Including the scrollable distance in every directions. You can scroll *the element* in case some area are overflowed.\n- If a captcha appears, tell user you can not solve captcha. finished the task and ask user to solve it.\n- If expected elements are missing, try scrolling, or navigating back.\n- If the page is not fully loaded, use the `wait` action.\n- Do not repeat one action for more than 3 times unless some conditions changed.\n- If you fill an input field and your action sequence is interrupted, most often something changed e.g. suggestions popped up under the field.\n- If the <user_request> includes specific page information such as product type, rating, price, location, etc., try to apply filters to be more efficient.\n- The <user_request> is the ultimate goal. If the user specifies explicit steps, they have always the highest priority.\n- If you input_text into a field, you might need to press enter, click the search button, or select from dropdown for completion.\n- Don\'t login into a page if you don\'t have to. Don\'t login if you don\'t have the credentials. \n- There are 2 types of tasks always first think which type of request you are dealing with:\n1. Very specific step by step instructions:\n- Follow them as very precise and don\'t skip steps. Try to complete everything as requested.\n2. Open ended tasks. Plan yourself, be creative in achieving them.\n- If you get stuck e.g. with logins or captcha in open-ended tasks you can re-evaluate the task and try alternative ways, e.g. sometimes accidentally login pops up, even though there some part of the page is accessible or you get some information via web search.\n</browser_rules>\n\n<capability>\n- You can only handle single page app. Do not jump out of current page.\n- Do not click on link if it will open in a new page (etc. <a target="_blank">)\n- It is ok to fail the task.\n - User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request.\n - Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It\'s encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user.\n - Trying to hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted result and harmful side-effects. User would rather you to complete the task with a fail.\n- If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps.\n</capability>\n\n<task_completion_rules>\nYou must call the `done` action in one of three cases:\n- When you have fully completed the USER REQUEST.\n- When you reach the final allowed step (`max_steps`), even if the task is incomplete.\n- When you feel stuck or unable to solve user request. Or user request is not clear or contains inappropriate content.\n- If it is ABSOLUTELY IMPOSSIBLE to continue.\n\nThe `done` action is your opportunity to terminate and share your findings with the user.\n- Set `success` to `true` only if the full USER REQUEST has been completed with no missing components.\n- If any part of the request is missing, incomplete, or uncertain, set `success` to `false`.\n- You can use the `text` field of the `done` action to communicate your findings and to provide a coherent reply to the user and fulfill the USER REQUEST.\n- You are ONLY ALLOWED to call `done` as a single action. Don\'t call it together with other actions.\n- If the user asks for specified format, such as "return JSON with following structure", "return a list of format...", MAKE sure to use the right format in your answer.\n- If the user asks for a structured output, your `done` action\'s schema may be modified. Take this schema into account when solving the task!\n</task_completion_rules>\n\n<reasoning_rules>\nExhibit the following reasoning patterns to successfully achieve the <user_request>:\n\n- Reason about <agent_history> to track progress and context toward <user_request>.\n- Analyze the most recent "Next Goal" and "Action Result" in <agent_history> and clearly state what you previously tried to achieve.\n- Analyze all relevant items in <agent_history> and <browser_state> to understand your state.\n- Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery.\n- Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help.\n- Ask user for help if you have any difficulty. Keep user in the loop.\n- If you see information relevant to <user_request>, plan saving the information to memory.\n- Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it.\n</reasoning_rules>\n\n<examples>\nHere are examples of good output patterns. Use them as reference but never copy them directly.\n\n<evaluation_examples>\n- Positive Examples:\n"evaluation_previous_goal": "Successfully navigated to the product page and found the target information. Verdict: Success"\n"evaluation_previous_goal": "Clicked the login button and user authentication form appeared. Verdict: Success"\n</evaluation_examples>\n\n<memory_examples>\n"memory": "Found many pending reports that need to be analyzed in the main page. Successfully processed the first 2 reports on quarterly sales data and moving on to inventory analysis and customer feedback reports."\n</memory_examples>\n\n<next_goal_examples>\n"next_goal": "Click on the \'Add to Cart\' button to proceed with the purchase flow."\n"next_goal": "Extract details from the first item on the page."\n</next_goal_examples>\n</examples>\n\n<output>\nYou must ALWAYS respond with a valid JSON in this exact format:\n\n{\n "evaluation_previous_goal": "Concise one-sentence analysis of your last action. Clearly state success, failure, or uncertain.",\n "memory": "1-3 concise sentences of specific memory of this step and overall progress. You should put here everything that will help you track progress in future steps. Like counting pages visited, items found, etc.",\n "next_goal": "State the next immediate goal and action to achieve it, in one clear sentence."\n "action":{"one_action_name": {// action-specific parameter}}\n}\n</output>\n';
|
|
21
21
|
function normalizeResponse(response) {
|
|
22
22
|
let resolvedArguments = null;
|
|
23
23
|
const choice = response.choices?.[0];
|
|
@@ -193,6 +193,9 @@ tools.set(
|
|
|
193
193
|
question: zod.string()
|
|
194
194
|
}),
|
|
195
195
|
execute: /* @__PURE__ */ __name(async function(input) {
|
|
196
|
+
if (!this.panel) {
|
|
197
|
+
throw new Error("ask_user tool requires panel to be enabled");
|
|
198
|
+
}
|
|
196
199
|
const answer = await this.panel.askUser(input.question);
|
|
197
200
|
return `✅ Received user answer: ${answer}`;
|
|
198
201
|
}, "execute")
|
|
@@ -300,7 +303,7 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
300
303
|
__privateAdd(this, _PageAgent_instances);
|
|
301
304
|
__publicField(this, "config");
|
|
302
305
|
__publicField(this, "id", uid());
|
|
303
|
-
__publicField(this, "panel");
|
|
306
|
+
__publicField(this, "panel", null);
|
|
304
307
|
__publicField(this, "tools");
|
|
305
308
|
__publicField(this, "disposed", false);
|
|
306
309
|
__publicField(this, "task", "");
|
|
@@ -319,15 +322,18 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
319
322
|
/** Last known URL for detecting navigation */
|
|
320
323
|
lastURL: ""
|
|
321
324
|
});
|
|
322
|
-
/** History
|
|
325
|
+
/** History events */
|
|
323
326
|
__publicField(this, "history", []);
|
|
324
327
|
this.config = config;
|
|
325
328
|
__privateSet(this, _llm, new LLM(this.config));
|
|
326
|
-
this.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
329
|
+
if (this.config.enablePanel !== false) {
|
|
330
|
+
this.panel = new Panel({
|
|
331
|
+
language: this.config.language,
|
|
332
|
+
onExecuteTask: /* @__PURE__ */ __name((task) => this.execute(task), "onExecuteTask"),
|
|
333
|
+
onStop: /* @__PURE__ */ __name(() => this.dispose(), "onStop"),
|
|
334
|
+
promptForNextTask: this.config.promptForNextTask
|
|
335
|
+
});
|
|
336
|
+
}
|
|
331
337
|
this.tools = new Map(tools);
|
|
332
338
|
this.pageController = new PageController({
|
|
333
339
|
...this.config,
|
|
@@ -335,11 +341,11 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
335
341
|
});
|
|
336
342
|
__privateSet(this, _llmRetryListener, (e) => {
|
|
337
343
|
const { current, max } = e.detail;
|
|
338
|
-
this.panel
|
|
344
|
+
this.panel?.update({ type: "retry", current, max });
|
|
339
345
|
});
|
|
340
346
|
__privateSet(this, _llmErrorListener, (e) => {
|
|
341
347
|
const { error } = e.detail;
|
|
342
|
-
this.panel
|
|
348
|
+
this.panel?.update({ type: "error", message: `step failed: ${error.message}` });
|
|
343
349
|
});
|
|
344
350
|
__privateGet(this, _llm).addEventListener("retry", __privateGet(this, _llmRetryListener));
|
|
345
351
|
__privateGet(this, _llm).addEventListener("error", __privateGet(this, _llmErrorListener));
|
|
@@ -355,6 +361,9 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
355
361
|
if (!this.config.experimentalScriptExecutionTool) {
|
|
356
362
|
this.tools.delete("execute_javascript");
|
|
357
363
|
}
|
|
364
|
+
if (this.config.enableAskUser === false || this.config.enablePanel === false) {
|
|
365
|
+
this.tools.delete("ask_user");
|
|
366
|
+
}
|
|
358
367
|
__privateSet(this, _beforeUnloadListener, (e) => {
|
|
359
368
|
if (!this.disposed) this.dispose("PAGE_UNLOADING");
|
|
360
369
|
});
|
|
@@ -366,7 +375,7 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
366
375
|
*/
|
|
367
376
|
pushObservation(content) {
|
|
368
377
|
this.history.push({ type: "observation", content });
|
|
369
|
-
this.panel
|
|
378
|
+
this.panel?.update({ type: "observation", content });
|
|
370
379
|
}
|
|
371
380
|
async execute(task) {
|
|
372
381
|
if (!task) throw new Error("Task is required");
|
|
@@ -378,9 +387,9 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
378
387
|
const onAfterTask = this.config.onAfterTask || (() => void 0);
|
|
379
388
|
await onBeforeTask.call(this);
|
|
380
389
|
this.pageController.showMask();
|
|
381
|
-
this.panel
|
|
382
|
-
this.panel
|
|
383
|
-
this.panel
|
|
390
|
+
this.panel?.show();
|
|
391
|
+
this.panel?.reset();
|
|
392
|
+
this.panel?.update({ type: "input", task: this.task });
|
|
384
393
|
if (__privateGet(this, _abortController)) {
|
|
385
394
|
__privateGet(this, _abortController).abort();
|
|
386
395
|
__privateSet(this, _abortController, new AbortController());
|
|
@@ -398,7 +407,7 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
398
407
|
console.group(`step: ${step}`);
|
|
399
408
|
if (__privateGet(this, _abortController).signal.aborted) throw new Error("AbortError");
|
|
400
409
|
console.log(chalk.blue("Thinking..."));
|
|
401
|
-
this.panel
|
|
410
|
+
this.panel?.update({ type: "thinking" });
|
|
402
411
|
const result = await __privateGet(this, _llm).invoke(
|
|
403
412
|
[
|
|
404
413
|
{
|
|
@@ -481,7 +490,7 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
481
490
|
console.log("Disposing PageAgent...");
|
|
482
491
|
this.disposed = true;
|
|
483
492
|
this.pageController.dispose();
|
|
484
|
-
this.panel
|
|
493
|
+
this.panel?.dispose();
|
|
485
494
|
this.history = [];
|
|
486
495
|
__privateGet(this, _abortController).abort(reason ?? "PageAgent disposed");
|
|
487
496
|
if (__privateGet(this, _llmRetryListener)) {
|
|
@@ -546,12 +555,12 @@ packMacroTool_fn = /* @__PURE__ */ __name(function() {
|
|
|
546
555
|
const reflectionText = reflectionLines.length > 0 ? reflectionLines.join("\n") : "";
|
|
547
556
|
if (reflectionText) {
|
|
548
557
|
console.log(reflectionText);
|
|
549
|
-
this.panel
|
|
558
|
+
this.panel?.update({ type: "thinking", text: reflectionText });
|
|
550
559
|
}
|
|
551
560
|
const tool2 = tools2.get(toolName);
|
|
552
561
|
assert(tool2, `Tool ${toolName} not found. (@note should have been caught before this!!!)`);
|
|
553
562
|
console.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput);
|
|
554
|
-
this.panel
|
|
563
|
+
this.panel?.update({ type: "toolExecuting", toolName, args: toolInput });
|
|
555
564
|
const startTime = Date.now();
|
|
556
565
|
const result = await tool2.execute.bind(this)(toolInput);
|
|
557
566
|
const duration = Date.now() - startTime;
|
|
@@ -559,7 +568,7 @@ packMacroTool_fn = /* @__PURE__ */ __name(function() {
|
|
|
559
568
|
if (toolName !== "wait") {
|
|
560
569
|
this.states.totalWaitTime = 0;
|
|
561
570
|
}
|
|
562
|
-
this.panel
|
|
571
|
+
this.panel?.update({
|
|
563
572
|
type: "toolCompleted",
|
|
564
573
|
toolName,
|
|
565
574
|
args: toolInput,
|
|
@@ -677,11 +686,11 @@ assembleUserPrompt_fn = /* @__PURE__ */ __name(async function() {
|
|
|
677
686
|
onDone_fn = /* @__PURE__ */ __name(function(text, success = true) {
|
|
678
687
|
this.pageController.cleanUpHighlights();
|
|
679
688
|
if (success) {
|
|
680
|
-
this.panel
|
|
689
|
+
this.panel?.update({ type: "output", text });
|
|
681
690
|
} else {
|
|
682
|
-
this.panel
|
|
691
|
+
this.panel?.update({ type: "error", message: text });
|
|
683
692
|
}
|
|
684
|
-
this.panel
|
|
693
|
+
this.panel?.update({ type: "completed" });
|
|
685
694
|
this.pageController.hideMask();
|
|
686
695
|
__privateGet(this, _abortController).abort();
|
|
687
696
|
}, "#onDone");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-agent.js","sources":["../../src/config/constants.ts","../../src/prompts/system_prompt.md?raw","../../src/utils/autoFixer.ts","../../src/utils/index.ts","../../src/tools/index.ts","../../src/utils/assert.ts","../../src/PageAgent.ts"],"sourcesContent":["// Agent-specific constants (LLM constants moved to @page-agent/llms)\nexport const MAX_STEPS = 20\n","export default \"You are an AI agent designed to operate in an iterative loop to automate browser tasks. Your ultimate goal is accomplishing the task provided in <user_request>.\\n\\n<intro>\\nYou excel at following tasks:\\n1. Navigating complex websites and extracting precise information\\n2. Automating form submissions and interactive web actions\\n3. Gathering and saving information \\n4. Operate effectively in an agent loop\\n5. Efficiently performing diverse web tasks\\n</intro>\\n\\n<language_settings>\\n- Default working language: **中文**\\n- Use the language that user is using. Return in user's language.\\n</language_settings>\\n\\n<input>\\nAt every step, your input will consist of: \\n1. <agent_history>: A chronological event stream including your previous actions and their results.\\n2. <agent_state>: Current <user_request> and <step_info>.\\n3. <browser_state>: Current URL, interactive elements indexed for actions, and visible page content.\\n</input>\\n\\n<agent_history>\\nAgent history will be given as a list of step information as follows:\\n\\n<step_{step_number}>:\\nEvaluation of Previous Step: Assessment of last action\\nMemory: Your memory of this step\\nNext Goal: Your goal for this step\\nAction Results: Your actions and their results\\n</step_{step_number}>\\n\\nand system messages wrapped in <sys> tag.\\n</agent_history>\\n\\n<user_request>\\nUSER REQUEST: This is your ultimate objective and always remains visible.\\n- This has the highest priority. Make the user happy.\\n- If the user request is very specific - then carefully follow each step and dont skip or hallucinate steps.\\n- If the task is open ended you can plan yourself how to get it done.\\n</user_request>\\n\\n<browser_state>\\n1. Browser State will be given as:\\n\\nCurrent URL: URL of the page you are currently viewing.\\nInteractive Elements: All interactive elements will be provided in format as [index]<type>text</type> where\\n- index: Numeric identifier for interaction\\n- type: HTML element type (button, input, etc.)\\n- text: Element description\\n\\nExamples:\\n[33]<div>User form</div>\\n\\\\t*[35]<button aria-label='Submit form'>Submit</button>\\n\\nNote that:\\n- Only elements with numeric indexes in [] are interactive\\n- (stacked) indentation (with \\\\t) is important and means that the element is a (html) child of the element above (with a lower index)\\n- Elements tagged with `*[` are the new clickable elements that appeared on the website since the last step - if url has not changed.\\n- Pure text elements without [] are not interactive.\\n</browser_state>\\n\\n<browser_rules>\\nStrictly follow these rules while using the browser and navigating the web:\\n- Only interact with elements that have a numeric [index] assigned.\\n- Only use indexes that are explicitly provided.\\n- If the page changes after, for example, an input text action, analyze if you need to interact with new elements, e.g. selecting the right option from the list.\\n- By default, only elements in the visible viewport are listed. Use scrolling actions if you suspect relevant content is offscreen which you need to interact with. Scroll ONLY if there are more pixels below or above the page.\\n- You can scroll by a specific number of pages using the num_pages parameter (e.g., 0.5 for half page, 2.0 for two pages).\\n- All the elements that are scrollable are marked with `data-scrollable` attribute. Including the scrollable distance in every directions. You can scroll *the element* in case some area are overflowed.\\n- If a captcha appears, tell user you can not solve captcha. finished the task and ask user to solve it.\\n- If expected elements are missing, try scrolling, or navigating back.\\n- If the page is not fully loaded, use the `wait` action.\\n- Do not repeat one action for more than 3 times unless some conditions changed.\\n- If you fill an input field and your action sequence is interrupted, most often something changed e.g. suggestions popped up under the field.\\n- If the <user_request> includes specific page information such as product type, rating, price, location, etc., try to apply filters to be more efficient.\\n- The <user_request> is the ultimate goal. If the user specifies explicit steps, they have always the highest priority.\\n- If you input_text into a field, you might need to press enter, click the search button, or select from dropdown for completion.\\n- Don't login into a page if you don't have to. Don't login if you don't have the credentials. \\n- There are 2 types of tasks always first think which type of request you are dealing with:\\n1. Very specific step by step instructions:\\n- Follow them as very precise and don't skip steps. Try to complete everything as requested.\\n2. Open ended tasks. Plan yourself, be creative in achieving them.\\n- If you get stuck e.g. with logins or captcha in open-ended tasks you can re-evaluate the task and try alternative ways, e.g. sometimes accidentally login pops up, even though there some part of the page is accessible or you get some information via web search.\\n</browser_rules>\\n\\n<capability>\\n- You can only handle single page app. Do not jump out of current page.\\n- Do not click on link if it will open in a new page (etc. <a target=\\\"_blank\\\">)\\n- It is ok to fail the task.\\n\\t- User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request.\\n\\t- Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It's encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user.\\n\\t- Trying to hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted result and harmful side-effects. User would rather you to complete the task with a fail.\\n- If you are not clear about the request or steps. `ask_user` to clarify it.\\n- If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps.\\n</capability>\\n\\n<task_completion_rules>\\nYou must call the `done` action in one of three cases:\\n- When you have fully completed the USER REQUEST.\\n- When you reach the final allowed step (`max_steps`), even if the task is incomplete.\\n- When you feel stuck or unable to solve user request. Or user request is not clear or contains inappropriate content.\\n- If it is ABSOLUTELY IMPOSSIBLE to continue.\\n\\nThe `done` action is your opportunity to terminate and share your findings with the user.\\n- Set `success` to `true` only if the full USER REQUEST has been completed with no missing components.\\n- If any part of the request is missing, incomplete, or uncertain, set `success` to `false`.\\n- You can use the `text` field of the `done` action to communicate your findings and to provide a coherent reply to the user and fulfill the USER REQUEST.\\n- You are ONLY ALLOWED to call `done` as a single action. Don't call it together with other actions.\\n- If the user asks for specified format, such as \\\"return JSON with following structure\\\", \\\"return a list of format...\\\", MAKE sure to use the right format in your answer.\\n- If the user asks for a structured output, your `done` action's schema may be modified. Take this schema into account when solving the task!\\n</task_completion_rules>\\n\\n<reasoning_rules>\\nExhibit the following reasoning patterns to successfully achieve the <user_request>:\\n\\n- Reason about <agent_history> to track progress and context toward <user_request>.\\n- Analyze the most recent \\\"Next Goal\\\" and \\\"Action Result\\\" in <agent_history> and clearly state what you previously tried to achieve.\\n- Analyze all relevant items in <agent_history> and <browser_state> to understand your state.\\n- Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery.\\n- Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help.\\n- `ask_user` for help if you have any difficulty. Users want to be kept in the loop.\\n- If you see information relevant to <user_request>, plan saving the information to memory.\\n- Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it.\\n</reasoning_rules>\\n\\n<examples>\\nHere are examples of good output patterns. Use them as reference but never copy them directly.\\n\\n<evaluation_examples>\\n- Positive Examples:\\n\\\"evaluation_previous_goal\\\": \\\"Successfully navigated to the product page and found the target information. Verdict: Success\\\"\\n\\\"evaluation_previous_goal\\\": \\\"Clicked the login button and user authentication form appeared. Verdict: Success\\\"\\n</evaluation_examples>\\n\\n<memory_examples>\\n\\\"memory\\\": \\\"Found many pending reports that need to be analyzed in the main page. Successfully processed the first 2 reports on quarterly sales data and moving on to inventory analysis and customer feedback reports.\\\"\\n</memory_examples>\\n\\n<next_goal_examples>\\n\\\"next_goal\\\": \\\"Click on the 'Add to Cart' button to proceed with the purchase flow.\\\"\\n\\\"next_goal\\\": \\\"Extract details from the first item on the page.\\\"\\n</next_goal_examples>\\n</examples>\\n\\n<output>\\nYou must ALWAYS respond with a valid JSON in this exact format:\\n\\n{\\n \\\"evaluation_previous_goal\\\": \\\"Concise one-sentence analysis of your last action. Clearly state success, failure, or uncertain.\\\",\\n \\\"memory\\\": \\\"1-3 concise sentences of specific memory of this step and overall progress. You should put here everything that will help you track progress in future steps. Like counting pages visited, items found, etc.\\\",\\n \\\"next_goal\\\": \\\"State the next immediate goal and action to achieve it, in one clear sentence.\\\"\\n \\\"action\\\":{\\\"one_action_name\\\": {// action-specific parameter}}\\n}\\n</output>\\n\"","import chalk from 'chalk'\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 * - etc.\n */\nexport function normalizeResponse(response: any): any {\n\tlet resolvedArguments = null as 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\tconsole.log(chalk.yellow(`[normalizeResponse] #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\tconsole.log(chalk.yellow(`[normalizeResponse] #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\tconsole.log(chalk.yellow(`[normalizeResponse] #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\tconsole.log(chalk.yellow(`[normalizeResponse] #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// fix incomplete formats\n\tif (!resolvedArguments.action) {\n\t\tconsole.log(chalk.yellow(`[normalizeResponse] #5: fixing tool_call`))\n\t\tresolvedArguments.action = { name: 'wait', input: { 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 * 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","export { normalizeResponse } from './autoFixer'\n\n/**\n * Wait until condition becomes true\n * @returns Returns when condition becomes true, throws otherwise\n * @param timeout Timeout in milliseconds, default 0 means no timeout, throws error on timeout\n */\nexport async function waitUntil(check: () => boolean, timeout = 60 * 60_1000): Promise<boolean> {\n\tif (check()) return true\n\n\treturn new Promise((resolve, reject) => {\n\t\tconst start = Date.now()\n\t\tconst interval = setInterval(() => {\n\t\t\tif (check()) {\n\t\t\t\tclearInterval(interval)\n\t\t\t\tresolve(true)\n\t\t\t} else if (Date.now() - start > timeout) {\n\t\t\t\tclearInterval(interval)\n\t\t\t\treject(new Error('Timeout waiting for condition to become true'))\n\t\t\t}\n\t\t}, 100)\n\t})\n}\n\nexport async function waitFor(seconds: number): Promise<void> {\n\tawait new Promise((resolve) => setTimeout(resolve, seconds * 1000))\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 trimLines(text: string): string {\n\treturn text\n\t\t.split('\\n')\n\t\t.map((line) => line.trim())\n\t\t.join('\\n')\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 try')\n\t\t}\n\t}\n\n\treturn id\n}\n\n//\n\nif (!window.__PAGE_AGENT_IDS__) {\n\twindow.__PAGE_AGENT_IDS__ = []\n}\n\nconst ids = window.__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","/**\n * Internal tools for PageAgent.\n * @note Adapted from browser-use\n */\nimport zod, { type z } from 'zod'\n\nimport type { PageAgent } from '../PageAgent'\nimport { waitFor } from '../utils'\n\n/**\n * Internal tool definition that has access to PageAgent `this` context\n */\nexport interface PageAgentTool<TParams = any> {\n\t// name: string\n\tdescription: string\n\tinputSchema: z.ZodType<TParams>\n\texecute: (this: PageAgent, args: TParams) => Promise<string>\n}\n\nexport function tool<TParams>(options: PageAgentTool<TParams>): PageAgentTool<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, PageAgentTool>()\n\ntools.set(\n\t'done',\n\ttool({\n\t\tdescription:\n\t\t\t'Complete task - provide a summary of results for the user. Set success=True if task completed successfully, false otherwise. Text should be your response to the user summarizing results.',\n\t\tinputSchema: zod.object({\n\t\t\ttext: zod.string(),\n\t\t\tsuccess: zod.boolean().default(true),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\t// @note main loop will handle this one\n\t\t\t// this.onDone(input.text, input.success)\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:\n\t\t\t'Wait for x seconds. default 1s (max 10 seconds, min 1 second). This can be used to wait until the page or data is fully loaded.',\n\t\tinputSchema: zod.object({\n\t\t\tseconds: zod.number().min(1).max(10).default(1),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst lastTimeUpdate = await this.pageController.getLastUpdateTime()\n\t\t\tconst actualWaitTime = Math.max(0, input.seconds - (Date.now() - lastTimeUpdate) / 1000)\n\t\t\tconsole.log(`actualWaitTime: ${actualWaitTime} seconds`)\n\t\t\tawait waitFor(actualWaitTime)\n\n\t\t\tthis.states.totalWaitTime += input.seconds\n\n\t\t\tif (this.states.totalWaitTime >= 3) {\n\t\t\t\tthis.pushObservation(\n\t\t\t\t\t`You have waited ${this.states.totalWaitTime} seconds accumulatively. Do NOT wait any longer unless you have a good reason.`\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn `✅ Waited for ${input.seconds} 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: zod.object({\n\t\t\tquestion: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst answer = await this.panel.askUser(input.question)\n\t\t\treturn `✅ Received user answer: ${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: zod.object({\n\t\t\tindex: zod.int().min(0),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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 input text into a input interactive element',\n\t\tinputSchema: zod.object({\n\t\t\tindex: zod.int().min(0),\n\t\t\ttext: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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: zod.object({\n\t\t\tindex: zod.int().min(0),\n\t\t\ttext: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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 the page by specified number of pages (set down=True to scroll down, down=False to scroll up, num_pages=number of pages to scroll like 0.5 for half page, 1.0 for one page, etc.). Optional index parameter to scroll within a specific element or its scroll container (works well for dropdowns and custom UI components). Optional pixels parameter to scroll by a specific number of pixels instead of pages.',\n\t\tinputSchema: zod.object({\n\t\t\tdown: zod.boolean().default(true),\n\t\t\tnum_pages: zod.number().min(0).max(10).optional().default(0.1),\n\t\t\tpixels: zod.number().int().min(0).optional(),\n\t\t\tindex: zod.number().int().min(0).optional(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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\ntools.set(\n\t'scroll_horizontally',\n\ttool({\n\t\tdescription:\n\t\t\t'Scroll the page or element horizontally (set right=True to scroll right, right=False to scroll left, pixels=number of pixels to scroll). Optional index parameter to scroll within a specific element or its scroll container (works well for wide tables).',\n\t\tinputSchema: zod.object({\n\t\t\tright: zod.boolean().default(true),\n\t\t\tpixels: zod.number().int().min(0),\n\t\t\tindex: zod.number().int().min(0).optional(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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\tinputSchema: zod.object({\n\t\t\tscript: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.executeJavascript(input.script)\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\n// @todo get_dropdown_options\n// @todo select_dropdown_option\n// @todo send_keys\n// @todo upload_file\n// @todo go_back\n// @todo extract_structured_data\n","import chalk from 'chalk'\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 * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n */\nimport { LLM, type Tool } from '@page-agent/llms'\nimport { PageController } from '@page-agent/page-controller'\nimport { Panel } from '@page-agent/ui'\nimport chalk from 'chalk'\nimport zod from 'zod'\n\nimport type { PageAgentConfig } from './config'\nimport { MAX_STEPS } from './config/constants'\nimport SYSTEM_PROMPT from './prompts/system_prompt.md?raw'\nimport { tools } from './tools'\nimport { normalizeResponse, trimLines, uid } from './utils'\nimport { assert } from './utils/assert'\n\n/**\n * Agent reflection state - the reflection-before-action model\n *\n * Every tool call must first reflect on:\n * - evaluation_previous_goal: How well did the previous action achieve its goal?\n * - memory: Key information to remember for future steps\n * - next_goal: What should be accomplished in the next action?\n */\nexport interface AgentReflection {\n\tevaluation_previous_goal: string\n\tmemory: string\n\tnext_goal: string\n}\n\n/**\n * MacroTool input structure\n *\n * This is the core abstraction that enforces the \"reflection-before-action\" mental model.\n * Before executing any action, the LLM must output its reasoning state.\n */\nexport interface MacroToolInput extends Partial<AgentReflection> {\n\taction: Record<string, any>\n}\n\n/**\n * MacroTool output structure\n */\nexport interface MacroToolResult {\n\tinput: MacroToolInput\n\toutput: string\n}\n\nexport type { PageAgentConfig }\nexport { tool, type PageAgentTool } from './tools'\n\n/**\n * A single agent step with reflection and action\n */\nexport interface AgentStep {\n\ttype: 'step'\n\treflection: Partial<AgentReflection>\n\taction: {\n\t\tname: string\n\t\tinput: any\n\t\toutput: string\n\t}\n\tusage: {\n\t\tpromptTokens: number\n\t\tcompletionTokens: number\n\t\ttotalTokens: number\n\t\tcachedTokens?: number\n\t\treasoningTokens?: number\n\t}\n}\n\n/**\n * Persistent observation event (stays in memory)\n */\nexport interface ObservationEvent {\n\ttype: 'observation'\n\tcontent: string\n}\n\n/**\n * User takeover event\n */\nexport interface UserTakeoverEvent {\n\ttype: 'user_takeover'\n}\n\n/**\n * Union type for all history events\n */\nexport type HistoryEvent = AgentStep | ObservationEvent | UserTakeoverEvent\n\nexport interface ExecutionResult {\n\tsuccess: boolean\n\tdata: string\n\thistory: HistoryEvent[]\n}\n\nexport class PageAgent extends EventTarget {\n\tconfig: PageAgentConfig\n\tid = uid()\n\tpanel: Panel\n\ttools: typeof tools\n\tdisposed = false\n\ttask = ''\n\ttaskId = ''\n\n\t#llm: LLM\n\t#abortController = new AbortController()\n\t#llmRetryListener: ((e: Event) => void) | null = null\n\t#llmErrorListener: ((e: Event) => void) | null = null\n\t#beforeUnloadListener: ((e: Event) => void) | null = null\n\n\t/** PageController for DOM operations */\n\tpageController: PageController\n\n\t/** Runtime states for tracking across steps */\n\tstates = {\n\t\t/** Accumulated wait time in seconds, used by wait tool */\n\t\ttotalWaitTime: 0,\n\t\t/** Last known URL for detecting navigation */\n\t\tlastURL: '',\n\t}\n\n\t/** History event stream */\n\thistory: HistoryEvent[] = []\n\n\tconstructor(config: PageAgentConfig) {\n\t\tsuper()\n\n\t\tthis.config = config\n\t\tthis.#llm = new LLM(this.config)\n\t\tthis.panel = new Panel({\n\t\t\tlanguage: this.config.language,\n\t\t\tonExecuteTask: (task) => this.execute(task),\n\t\t\tonStop: () => this.dispose(),\n\t\t})\n\t\tthis.tools = new Map(tools)\n\n\t\t// Initialize PageController with config (mask enabled by default)\n\t\tthis.pageController = new PageController({\n\t\t\t...this.config,\n\t\t\tenableMask: this.config.enableMask ?? true,\n\t\t})\n\n\t\t// Listen to LLM events\n\t\tthis.#llmRetryListener = (e) => {\n\t\t\tconst { current, max } = (e as CustomEvent).detail\n\t\t\tthis.panel.update({ type: 'retry', current, max })\n\t\t}\n\t\tthis.#llmErrorListener = (e) => {\n\t\t\tconst { error } = (e as CustomEvent).detail\n\t\t\tthis.panel.update({ type: 'error', message: `step failed: ${error.message}` })\n\t\t}\n\t\tthis.#llm.addEventListener('retry', this.#llmRetryListener)\n\t\tthis.#llm.addEventListener('error', this.#llmErrorListener)\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\n\t\tthis.#beforeUnloadListener = (e) => {\n\t\t\tif (!this.disposed) this.dispose('PAGE_UNLOADING')\n\t\t}\n\t\twindow.addEventListener('beforeunload', this.#beforeUnloadListener)\n\t}\n\n\t/**\n\t * Push a persistent observation to the history event stream.\n\t * This will be visible in <agent_history> and remain in memory across steps.\n\t */\n\tpushObservation(content: string): void {\n\t\tthis.history.push({ type: 'observation', content })\n\t\tthis.panel.update({ type: 'observation', content })\n\t}\n\n\tasync execute(task: string): Promise<ExecutionResult> {\n\t\tif (!task) throw new Error('Task is required')\n\t\tthis.task = task\n\t\tthis.taskId = uid()\n\n\t\tconst onBeforeStep = this.config.onBeforeStep || (() => void 0)\n\t\tconst onAfterStep = this.config.onAfterStep || (() => void 0)\n\t\tconst onBeforeTask = this.config.onBeforeTask || (() => void 0)\n\t\tconst onAfterTask = this.config.onAfterTask || (() => void 0)\n\n\t\tawait onBeforeTask.call(this)\n\n\t\t// Show mask and panel\n\t\tthis.pageController.showMask()\n\n\t\tthis.panel.show()\n\t\tthis.panel.reset()\n\n\t\tthis.panel.update({ type: 'input', task: this.task })\n\n\t\tif (this.#abortController) {\n\t\t\tthis.#abortController.abort()\n\t\t\tthis.#abortController = new AbortController()\n\t\t}\n\n\t\tthis.history = []\n\n\t\t// Reset states\n\t\tthis.states = {\n\t\t\ttotalWaitTime: 0,\n\t\t\tlastURL: '',\n\t\t}\n\n\t\ttry {\n\t\t\tlet step = 0\n\n\t\t\twhile (true) {\n\t\t\t\tawait this.#generateObservations(step)\n\n\t\t\t\tawait onBeforeStep.call(this, step)\n\n\t\t\t\tconsole.group(`step: ${step}`)\n\n\t\t\t\t// abort\n\t\t\t\tif (this.#abortController.signal.aborted) throw new Error('AbortError')\n\n\t\t\t\t// Update status to thinking\n\t\t\t\tconsole.log(chalk.blue('Thinking...'))\n\t\t\t\tthis.panel.update({ type: 'thinking' })\n\n\t\t\t\tconst result = await this.#llm.invoke(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trole: 'system',\n\t\t\t\t\t\t\tcontent: this.#getSystemPrompt(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trole: 'user',\n\t\t\t\t\t\t\tcontent: await this.#assembleUserPrompt(),\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t{ AgentOutput: this.#packMacroTool() },\n\t\t\t\t\tthis.#abortController.signal,\n\t\t\t\t\t{\n\t\t\t\t\t\ttoolChoiceName: 'AgentOutput',\n\t\t\t\t\t\tnormalizeResponse,\n\t\t\t\t\t}\n\t\t\t\t)\n\n\t\t\t\tconst macroResult = result.toolResult as MacroToolResult\n\t\t\t\tconst input = macroResult.input\n\t\t\t\tconst output = macroResult.output\n\t\t\t\tconst reflection: Partial<AgentReflection> = {\n\t\t\t\t\tevaluation_previous_goal: input.evaluation_previous_goal,\n\t\t\t\t\tmemory: input.memory,\n\t\t\t\t\tnext_goal: input.next_goal,\n\t\t\t\t}\n\t\t\t\tconst actionName = Object.keys(input.action)[0]\n\t\t\t\tconst action: AgentStep['action'] = {\n\t\t\t\t\tname: actionName,\n\t\t\t\t\tinput: input.action[actionName],\n\t\t\t\t\toutput: output,\n\t\t\t\t}\n\n\t\t\t\tthis.history.push({\n\t\t\t\t\ttype: 'step',\n\t\t\t\t\treflection,\n\t\t\t\t\taction,\n\t\t\t\t\tusage: result.usage,\n\t\t\t\t} as AgentStep)\n\n\t\t\t\tconsole.log(chalk.green('Step finished:'), actionName)\n\t\t\t\tconsole.groupEnd()\n\n\t\t\t\tawait onAfterStep.call(this, step, this.history)\n\n\t\t\t\tstep++\n\t\t\t\tif (step > MAX_STEPS) {\n\t\t\t\t\tthis.#onDone('Step count exceeded maximum limit', false)\n\t\t\t\t\tconst result: ExecutionResult = {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tdata: 'Step count exceeded maximum limit',\n\t\t\t\t\t\thistory: this.history,\n\t\t\t\t\t}\n\t\t\t\t\tawait onAfterTask.call(this, result)\n\t\t\t\t\treturn result\n\t\t\t\t}\n\t\t\t\tif (actionName === 'done') {\n\t\t\t\t\tconst success = action.input?.success ?? false\n\t\t\t\t\tconst text = action.input?.text || 'no text provided'\n\t\t\t\t\tconsole.log(chalk.green.bold('Task completed'), success, text)\n\t\t\t\t\tthis.#onDone(text, success)\n\t\t\t\t\tconst result: ExecutionResult = {\n\t\t\t\t\t\tsuccess,\n\t\t\t\t\t\tdata: text,\n\t\t\t\t\t\thistory: this.history,\n\t\t\t\t\t}\n\t\t\t\t\tawait onAfterTask.call(this, result)\n\t\t\t\t\treturn result\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tconsole.error('Task failed', error)\n\t\t\tthis.#onDone(String(error), false)\n\t\t\tconst result: ExecutionResult = {\n\t\t\t\tsuccess: false,\n\t\t\t\tdata: String(error),\n\t\t\t\thistory: this.history,\n\t\t\t}\n\t\t\tawait onAfterTask.call(this, result)\n\t\t\treturn result\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 zod.object({ [toolName]: tool.inputSchema }).describe(tool.description)\n\t\t})\n\n\t\tconst actionSchema = zod.union(\n\t\t\tactionSchemas as unknown as [zod.ZodType, zod.ZodType, ...zod.ZodType[]]\n\t\t)\n\n\t\tconst macroToolSchema = zod.object({\n\t\t\t// thinking: zod.string().optional(),\n\t\t\tevaluation_previous_goal: zod.string().optional(),\n\t\t\tmemory: zod.string().optional(),\n\t\t\tnext_goal: zod.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. Outputs your reflections and next action.',\n\t\t\tinputSchema: macroToolSchema as zod.ZodType<MacroToolInput>,\n\t\t\texecute: async (input: MacroToolInput): Promise<MacroToolResult> => {\n\t\t\t\t// abort\n\t\t\t\tif (this.#abortController.signal.aborted) throw new Error('AbortError')\n\n\t\t\t\tconsole.log(chalk.blue.bold('MacroTool execute'), 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\tthis.panel.update({ type: 'thinking', text: 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. (@note should have been caught before this!!!)`)\n\n\t\t\t\tconsole.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput)\n\t\t\t\tthis.panel.update({ type: 'toolExecuting', toolName, args: toolInput })\n\n\t\t\t\tconst startTime = Date.now()\n\n\t\t\t\t// Execute tool, bind `this` to PageAgent\n\t\t\t\tconst result = await tool.execute.bind(this)(toolInput)\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// Reset wait time for non-wait tools\n\t\t\t\tif (toolName !== 'wait') {\n\t\t\t\t\tthis.states.totalWaitTime = 0\n\t\t\t\t}\n\n\t\t\t\t// Briefly display execution result\n\t\t\t\tthis.panel.update({\n\t\t\t\t\ttype: 'toolCompleted',\n\t\t\t\t\ttoolName,\n\t\t\t\t\targs: toolInput,\n\t\t\t\t\tresult,\n\t\t\t\t\tduration,\n\t\t\t\t})\n\n\t\t\t\t// Wait a moment to let user see the result\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100))\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\tlet systemPrompt = SYSTEM_PROMPT\n\n\t\tconst targetLanguage = this.config.language === 'zh-CN' ? '中文' : 'English'\n\t\tsystemPrompt = systemPrompt.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 and format as XML block\n\t */\n\tasync #getInstructions(): Promise<string> {\n\t\tconst { instructions } = this.config\n\t\tif (!instructions) return ''\n\n\t\tconst systemInstructions = instructions.system?.trim()\n\t\tconst url = await this.pageController.getCurrentUrl()\n\t\tlet pageInstructions: string | undefined\n\n\t\tif (instructions.getPageInstructions) {\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\t\tif (!systemInstructions && !pageInstructions) 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\tresult += '</instructions>\\n\\n'\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Generate observations before each step\n\t * - URL change detection\n\t * - Too many steps warning\n\t * @todo loop detection\n\t * @todo console error\n\t */\n\tasync #generateObservations(stepCount: number): Promise<void> {\n\t\t// Detect URL change\n\t\tconst currentURL = await this.pageController.getCurrentUrl()\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}\n\n\t\t// Warn about remaining steps\n\t\tconst remaining = MAX_STEPS - stepCount\n\t\tif (remaining === 5) {\n\t\t\tthis.pushObservation(\n\t\t\t\t`⚠️ Only ${remaining} steps remaining. 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\t}\n\n\tasync #assembleUserPrompt(): Promise<string> {\n\t\tlet prompt = ''\n\n\t\t// <instructions> (optional)\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\t\t\t<user_request>\n\t\t\t${this.task}\n\t\t\t</user_request>\n\t\t\t<step_info>\n\t\t\tStep ${stepCount + 1} of ${MAX_STEPS} max possible steps\n\t\t\tCurrent date and time: ${new Date().toISOString()}\n\t\t\t</step_info>\n\t\t\t</agent_state>\n\t\t`\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 += '\\n<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\t\t\t\tEvaluation of Previous Step: ${event.reflection.evaluation_previous_goal}\n\t\t\t\tMemory: ${event.reflection.memory}\n\t\t\t\tNext Goal: ${event.reflection.next_goal}\n\t\t\t\tAction Results: ${event.action.output}\n\t\t\t\t</step_${stepIndex}>\n\t\t\t`\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}\n\t\t}\n\n\t\tprompt += '</agent_history>\\n\\n'\n\n\t\t// <browser_state>\n\n\t\tprompt += await this.#getBrowserState()\n\n\t\treturn trimLines(prompt)\n\t}\n\n\t#onDone(text: string, success = true) {\n\t\tthis.pageController.cleanUpHighlights()\n\n\t\t// Update panel status\n\t\tif (success) {\n\t\t\tthis.panel.update({ type: 'output', text })\n\t\t} else {\n\t\t\tthis.panel.update({ type: 'error', message: text })\n\t\t}\n\n\t\t// Task completed\n\t\tthis.panel.update({ type: 'completed' })\n\n\t\tthis.pageController.hideMask()\n\n\t\tthis.#abortController.abort()\n\t}\n\n\tasync #getBrowserState(): Promise<string> {\n\t\tconst state = await this.pageController.getBrowserState()\n\n\t\tlet content = state.content\n\t\tif (this.config.transformPageContent) {\n\t\t\tcontent = await this.config.transformPageContent(content)\n\t\t}\n\n\t\treturn trimLines(`<browser_state>\n\t\t\tCurrent Page: [${state.title}](${state.url})\n\n\t\t\t${state.header}\n\t\t\t${content}\n\t\t\t${state.footer}\n\n\t\t\t</browser_state>\n\t\t`)\n\t}\n\n\tdispose(reason?: string) {\n\t\tconsole.log('Disposing PageAgent...')\n\t\tthis.disposed = true\n\t\tthis.pageController.dispose()\n\t\tthis.panel.dispose()\n\t\tthis.history = []\n\t\tthis.#abortController.abort(reason ?? 'PageAgent disposed')\n\n\t\t// Clean up LLM event listeners\n\t\tif (this.#llmRetryListener) {\n\t\t\tthis.#llm.removeEventListener('retry', this.#llmRetryListener)\n\t\t\tthis.#llmRetryListener = null\n\t\t}\n\t\tif (this.#llmErrorListener) {\n\t\t\tthis.#llm.removeEventListener('error', this.#llmErrorListener)\n\t\t\tthis.#llmErrorListener = null\n\t\t}\n\n\t\t// Clean up window event listeners\n\t\tif (this.#beforeUnloadListener) {\n\t\t\twindow.removeEventListener('beforeunload', this.#beforeUnloadListener)\n\t\t\tthis.#beforeUnloadListener = null\n\t\t}\n\n\t\tthis.config.onDispose?.call(this, reason)\n\t}\n}\n"],"names":["tool","result","tools"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"page-agent.js","sources":["../../src/config/constants.ts","../../src/prompts/system_prompt.md?raw","../../src/utils/autoFixer.ts","../../src/utils/index.ts","../../src/tools/index.ts","../../src/utils/assert.ts","../../src/PageAgent.ts"],"sourcesContent":["// Agent-specific constants (LLM constants moved to @page-agent/llms)\nexport const MAX_STEPS = 20\n","export default \"You are an AI agent designed to operate in an iterative loop to automate browser tasks. Your ultimate goal is accomplishing the task provided in <user_request>.\\n\\n<intro>\\nYou excel at following tasks:\\n1. Navigating complex websites and extracting precise information\\n2. Automating form submissions and interactive web actions\\n3. Gathering and saving information \\n4. Operate effectively in an agent loop\\n5. Efficiently performing diverse web tasks\\n</intro>\\n\\n<language_settings>\\n- Default working language: **中文**\\n- Use the language that user is using. Return in user's language.\\n</language_settings>\\n\\n<input>\\nAt every step, your input will consist of: \\n1. <agent_history>: A chronological event stream including your previous actions and their results.\\n2. <agent_state>: Current <user_request> and <step_info>.\\n3. <browser_state>: Current URL, interactive elements indexed for actions, and visible page content.\\n</input>\\n\\n<agent_history>\\nAgent history will be given as a list of step information as follows:\\n\\n<step_{step_number}>:\\nEvaluation of Previous Step: Assessment of last action\\nMemory: Your memory of this step\\nNext Goal: Your goal for this step\\nAction Results: Your actions and their results\\n</step_{step_number}>\\n\\nand system messages wrapped in <sys> tag.\\n</agent_history>\\n\\n<user_request>\\nUSER REQUEST: This is your ultimate objective and always remains visible.\\n- This has the highest priority. Make the user happy.\\n- If the user request is very specific - then carefully follow each step and dont skip or hallucinate steps.\\n- If the task is open ended you can plan yourself how to get it done.\\n</user_request>\\n\\n<browser_state>\\n1. Browser State will be given as:\\n\\nCurrent URL: URL of the page you are currently viewing.\\nInteractive Elements: All interactive elements will be provided in format as [index]<type>text</type> where\\n- index: Numeric identifier for interaction\\n- type: HTML element type (button, input, etc.)\\n- text: Element description\\n\\nExamples:\\n[33]<div>User form</div>\\n\\\\t*[35]<button aria-label='Submit form'>Submit</button>\\n\\nNote that:\\n- Only elements with numeric indexes in [] are interactive\\n- (stacked) indentation (with \\\\t) is important and means that the element is a (html) child of the element above (with a lower index)\\n- Elements tagged with `*[` are the new clickable elements that appeared on the website since the last step - if url has not changed.\\n- Pure text elements without [] are not interactive.\\n</browser_state>\\n\\n<browser_rules>\\nStrictly follow these rules while using the browser and navigating the web:\\n- Only interact with elements that have a numeric [index] assigned.\\n- Only use indexes that are explicitly provided.\\n- If the page changes after, for example, an input text action, analyze if you need to interact with new elements, e.g. selecting the right option from the list.\\n- By default, only elements in the visible viewport are listed. Use scrolling actions if you suspect relevant content is offscreen which you need to interact with. Scroll ONLY if there are more pixels below or above the page.\\n- You can scroll by a specific number of pages using the num_pages parameter (e.g., 0.5 for half page, 2.0 for two pages).\\n- All the elements that are scrollable are marked with `data-scrollable` attribute. Including the scrollable distance in every directions. You can scroll *the element* in case some area are overflowed.\\n- If a captcha appears, tell user you can not solve captcha. finished the task and ask user to solve it.\\n- If expected elements are missing, try scrolling, or navigating back.\\n- If the page is not fully loaded, use the `wait` action.\\n- Do not repeat one action for more than 3 times unless some conditions changed.\\n- If you fill an input field and your action sequence is interrupted, most often something changed e.g. suggestions popped up under the field.\\n- If the <user_request> includes specific page information such as product type, rating, price, location, etc., try to apply filters to be more efficient.\\n- The <user_request> is the ultimate goal. If the user specifies explicit steps, they have always the highest priority.\\n- If you input_text into a field, you might need to press enter, click the search button, or select from dropdown for completion.\\n- Don't login into a page if you don't have to. Don't login if you don't have the credentials. \\n- There are 2 types of tasks always first think which type of request you are dealing with:\\n1. Very specific step by step instructions:\\n- Follow them as very precise and don't skip steps. Try to complete everything as requested.\\n2. Open ended tasks. Plan yourself, be creative in achieving them.\\n- If you get stuck e.g. with logins or captcha in open-ended tasks you can re-evaluate the task and try alternative ways, e.g. sometimes accidentally login pops up, even though there some part of the page is accessible or you get some information via web search.\\n</browser_rules>\\n\\n<capability>\\n- You can only handle single page app. Do not jump out of current page.\\n- Do not click on link if it will open in a new page (etc. <a target=\\\"_blank\\\">)\\n- It is ok to fail the task.\\n\\t- User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request.\\n\\t- Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It's encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user.\\n\\t- Trying to hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted result and harmful side-effects. User would rather you to complete the task with a fail.\\n- If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps.\\n</capability>\\n\\n<task_completion_rules>\\nYou must call the `done` action in one of three cases:\\n- When you have fully completed the USER REQUEST.\\n- When you reach the final allowed step (`max_steps`), even if the task is incomplete.\\n- When you feel stuck or unable to solve user request. Or user request is not clear or contains inappropriate content.\\n- If it is ABSOLUTELY IMPOSSIBLE to continue.\\n\\nThe `done` action is your opportunity to terminate and share your findings with the user.\\n- Set `success` to `true` only if the full USER REQUEST has been completed with no missing components.\\n- If any part of the request is missing, incomplete, or uncertain, set `success` to `false`.\\n- You can use the `text` field of the `done` action to communicate your findings and to provide a coherent reply to the user and fulfill the USER REQUEST.\\n- You are ONLY ALLOWED to call `done` as a single action. Don't call it together with other actions.\\n- If the user asks for specified format, such as \\\"return JSON with following structure\\\", \\\"return a list of format...\\\", MAKE sure to use the right format in your answer.\\n- If the user asks for a structured output, your `done` action's schema may be modified. Take this schema into account when solving the task!\\n</task_completion_rules>\\n\\n<reasoning_rules>\\nExhibit the following reasoning patterns to successfully achieve the <user_request>:\\n\\n- Reason about <agent_history> to track progress and context toward <user_request>.\\n- Analyze the most recent \\\"Next Goal\\\" and \\\"Action Result\\\" in <agent_history> and clearly state what you previously tried to achieve.\\n- Analyze all relevant items in <agent_history> and <browser_state> to understand your state.\\n- Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery.\\n- Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help.\\n- Ask user for help if you have any difficulty. Keep user in the loop.\\n- If you see information relevant to <user_request>, plan saving the information to memory.\\n- Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it.\\n</reasoning_rules>\\n\\n<examples>\\nHere are examples of good output patterns. Use them as reference but never copy them directly.\\n\\n<evaluation_examples>\\n- Positive Examples:\\n\\\"evaluation_previous_goal\\\": \\\"Successfully navigated to the product page and found the target information. Verdict: Success\\\"\\n\\\"evaluation_previous_goal\\\": \\\"Clicked the login button and user authentication form appeared. Verdict: Success\\\"\\n</evaluation_examples>\\n\\n<memory_examples>\\n\\\"memory\\\": \\\"Found many pending reports that need to be analyzed in the main page. Successfully processed the first 2 reports on quarterly sales data and moving on to inventory analysis and customer feedback reports.\\\"\\n</memory_examples>\\n\\n<next_goal_examples>\\n\\\"next_goal\\\": \\\"Click on the 'Add to Cart' button to proceed with the purchase flow.\\\"\\n\\\"next_goal\\\": \\\"Extract details from the first item on the page.\\\"\\n</next_goal_examples>\\n</examples>\\n\\n<output>\\nYou must ALWAYS respond with a valid JSON in this exact format:\\n\\n{\\n \\\"evaluation_previous_goal\\\": \\\"Concise one-sentence analysis of your last action. Clearly state success, failure, or uncertain.\\\",\\n \\\"memory\\\": \\\"1-3 concise sentences of specific memory of this step and overall progress. You should put here everything that will help you track progress in future steps. Like counting pages visited, items found, etc.\\\",\\n \\\"next_goal\\\": \\\"State the next immediate goal and action to achieve it, in one clear sentence.\\\"\\n \\\"action\\\":{\\\"one_action_name\\\": {// action-specific parameter}}\\n}\\n</output>\\n\"","import chalk from 'chalk'\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 * - etc.\n */\nexport function normalizeResponse(response: any): any {\n\tlet resolvedArguments = null as 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\tconsole.log(chalk.yellow(`[normalizeResponse] #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\tconsole.log(chalk.yellow(`[normalizeResponse] #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\tconsole.log(chalk.yellow(`[normalizeResponse] #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\tconsole.log(chalk.yellow(`[normalizeResponse] #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// fix incomplete formats\n\tif (!resolvedArguments.action) {\n\t\tconsole.log(chalk.yellow(`[normalizeResponse] #5: fixing tool_call`))\n\t\tresolvedArguments.action = { name: 'wait', input: { 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 * 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","export { normalizeResponse } from './autoFixer'\n\n/**\n * Wait until condition becomes true\n * @returns Returns when condition becomes true, throws otherwise\n * @param timeout Timeout in milliseconds, default 0 means no timeout, throws error on timeout\n */\nexport async function waitUntil(check: () => boolean, timeout = 60 * 60_1000): Promise<boolean> {\n\tif (check()) return true\n\n\treturn new Promise((resolve, reject) => {\n\t\tconst start = Date.now()\n\t\tconst interval = setInterval(() => {\n\t\t\tif (check()) {\n\t\t\t\tclearInterval(interval)\n\t\t\t\tresolve(true)\n\t\t\t} else if (Date.now() - start > timeout) {\n\t\t\t\tclearInterval(interval)\n\t\t\t\treject(new Error('Timeout waiting for condition to become true'))\n\t\t\t}\n\t\t}, 100)\n\t})\n}\n\nexport async function waitFor(seconds: number): Promise<void> {\n\tawait new Promise((resolve) => setTimeout(resolve, seconds * 1000))\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 trimLines(text: string): string {\n\treturn text\n\t\t.split('\\n')\n\t\t.map((line) => line.trim())\n\t\t.join('\\n')\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 try')\n\t\t}\n\t}\n\n\treturn id\n}\n\n//\n\nif (!window.__PAGE_AGENT_IDS__) {\n\twindow.__PAGE_AGENT_IDS__ = []\n}\n\nconst ids = window.__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","/**\n * Internal tools for PageAgent.\n * @note Adapted from browser-use\n */\nimport zod, { type z } from 'zod'\n\nimport type { PageAgent } from '../PageAgent'\nimport { waitFor } from '../utils'\n\n/**\n * Internal tool definition that has access to PageAgent `this` context\n */\nexport interface PageAgentTool<TParams = any> {\n\t// name: string\n\tdescription: string\n\tinputSchema: z.ZodType<TParams>\n\texecute: (this: PageAgent, args: TParams) => Promise<string>\n}\n\nexport function tool<TParams>(options: PageAgentTool<TParams>): PageAgentTool<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, PageAgentTool>()\n\ntools.set(\n\t'done',\n\ttool({\n\t\tdescription:\n\t\t\t'Complete task - provide a summary of results for the user. Set success=True if task completed successfully, false otherwise. Text should be your response to the user summarizing results.',\n\t\tinputSchema: zod.object({\n\t\t\ttext: zod.string(),\n\t\t\tsuccess: zod.boolean().default(true),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\t// @note main loop will handle this one\n\t\t\t// this.onDone(input.text, input.success)\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:\n\t\t\t'Wait for x seconds. default 1s (max 10 seconds, min 1 second). This can be used to wait until the page or data is fully loaded.',\n\t\tinputSchema: zod.object({\n\t\t\tseconds: zod.number().min(1).max(10).default(1),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst lastTimeUpdate = await this.pageController.getLastUpdateTime()\n\t\t\tconst actualWaitTime = Math.max(0, input.seconds - (Date.now() - lastTimeUpdate) / 1000)\n\t\t\tconsole.log(`actualWaitTime: ${actualWaitTime} seconds`)\n\t\t\tawait waitFor(actualWaitTime)\n\n\t\t\tthis.states.totalWaitTime += input.seconds\n\n\t\t\tif (this.states.totalWaitTime >= 3) {\n\t\t\t\tthis.pushObservation(\n\t\t\t\t\t`You have waited ${this.states.totalWaitTime} seconds accumulatively. Do NOT wait any longer unless you have a good reason.`\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn `✅ Waited for ${input.seconds} 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: zod.object({\n\t\t\tquestion: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tif (!this.panel) {\n\t\t\t\tthrow new Error('ask_user tool requires panel to be enabled')\n\t\t\t}\n\t\t\tconst answer = await this.panel.askUser(input.question)\n\t\t\treturn `✅ Received user answer: ${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: zod.object({\n\t\t\tindex: zod.int().min(0),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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 input text into a input interactive element',\n\t\tinputSchema: zod.object({\n\t\t\tindex: zod.int().min(0),\n\t\t\ttext: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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: zod.object({\n\t\t\tindex: zod.int().min(0),\n\t\t\ttext: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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 the page by specified number of pages (set down=True to scroll down, down=False to scroll up, num_pages=number of pages to scroll like 0.5 for half page, 1.0 for one page, etc.). Optional index parameter to scroll within a specific element or its scroll container (works well for dropdowns and custom UI components). Optional pixels parameter to scroll by a specific number of pixels instead of pages.',\n\t\tinputSchema: zod.object({\n\t\t\tdown: zod.boolean().default(true),\n\t\t\tnum_pages: zod.number().min(0).max(10).optional().default(0.1),\n\t\t\tpixels: zod.number().int().min(0).optional(),\n\t\t\tindex: zod.number().int().min(0).optional(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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\ntools.set(\n\t'scroll_horizontally',\n\ttool({\n\t\tdescription:\n\t\t\t'Scroll the page or element horizontally (set right=True to scroll right, right=False to scroll left, pixels=number of pixels to scroll). Optional index parameter to scroll within a specific element or its scroll container (works well for wide tables).',\n\t\tinputSchema: zod.object({\n\t\t\tright: zod.boolean().default(true),\n\t\t\tpixels: zod.number().int().min(0),\n\t\t\tindex: zod.number().int().min(0).optional(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.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\tinputSchema: zod.object({\n\t\t\tscript: zod.string(),\n\t\t}),\n\t\texecute: async function (this: PageAgent, input) {\n\t\t\tconst result = await this.pageController.executeJavascript(input.script)\n\t\t\treturn result.message\n\t\t},\n\t})\n)\n\n// @todo get_dropdown_options\n// @todo select_dropdown_option\n// @todo send_keys\n// @todo upload_file\n// @todo go_back\n// @todo extract_structured_data\n","import chalk from 'chalk'\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 * Copyright (C) 2025 Alibaba Group Holding Limited\n * All rights reserved.\n */\nimport { LLM, type Tool } from '@page-agent/llms'\nimport { PageController } from '@page-agent/page-controller'\nimport { Panel } from '@page-agent/ui'\nimport chalk from 'chalk'\nimport zod from 'zod'\n\nimport type { PageAgentConfig } from './config'\nimport { MAX_STEPS } from './config/constants'\nimport SYSTEM_PROMPT from './prompts/system_prompt.md?raw'\nimport { tools } from './tools'\nimport { normalizeResponse, trimLines, uid } from './utils'\nimport { assert } from './utils/assert'\n\n/**\n * Agent reflection state - the reflection-before-action model\n *\n * Every tool call must first reflect on:\n * - evaluation_previous_goal: How well did the previous action achieve its goal?\n * - memory: Key information to remember for future steps\n * - next_goal: What should be accomplished in the next action?\n */\nexport interface AgentReflection {\n\tevaluation_previous_goal: string\n\tmemory: string\n\tnext_goal: string\n}\n\n/**\n * MacroTool input structure\n *\n * This is the core abstraction that enforces the \"reflection-before-action\" mental model.\n * Before executing any action, the LLM must output its reasoning state.\n */\nexport interface MacroToolInput extends Partial<AgentReflection> {\n\taction: Record<string, any>\n}\n\n/**\n * MacroTool output structure\n */\nexport interface MacroToolResult {\n\tinput: MacroToolInput\n\toutput: string\n}\n\nexport type { PageAgentConfig }\nexport { tool, type PageAgentTool } from './tools'\n\n/**\n * A single agent step with reflection and action\n */\nexport interface AgentStep {\n\ttype: 'step'\n\treflection: Partial<AgentReflection>\n\taction: {\n\t\tname: string\n\t\tinput: any\n\t\toutput: string\n\t}\n\tusage: {\n\t\tpromptTokens: number\n\t\tcompletionTokens: number\n\t\ttotalTokens: number\n\t\tcachedTokens?: number\n\t\treasoningTokens?: number\n\t}\n}\n\n/**\n * Persistent observation event (stays in memory)\n */\nexport interface ObservationEvent {\n\ttype: 'observation'\n\tcontent: string\n}\n\n/**\n * User takeover event\n */\nexport interface UserTakeoverEvent {\n\ttype: 'user_takeover'\n}\n\n/**\n * Union type for all history events\n */\nexport type HistoryEvent = AgentStep | ObservationEvent | UserTakeoverEvent\n\nexport interface ExecutionResult {\n\tsuccess: boolean\n\tdata: string\n\thistory: HistoryEvent[]\n}\n\nexport class PageAgent extends EventTarget {\n\tconfig: PageAgentConfig\n\tid = uid()\n\tpanel: Panel | null = null\n\ttools: typeof tools\n\tdisposed = false\n\ttask = ''\n\ttaskId = ''\n\n\t#llm: LLM\n\t#abortController = new AbortController()\n\t#llmRetryListener: ((e: Event) => void) | null = null\n\t#llmErrorListener: ((e: Event) => void) | null = null\n\t#beforeUnloadListener: ((e: Event) => void) | null = null\n\n\t/** PageController for DOM operations */\n\tpageController: PageController\n\n\t/** Runtime states for tracking across steps */\n\tstates = {\n\t\t/** Accumulated wait time in seconds, used by wait tool */\n\t\ttotalWaitTime: 0,\n\t\t/** Last known URL for detecting navigation */\n\t\tlastURL: '',\n\t}\n\n\t/** History events */\n\thistory: HistoryEvent[] = []\n\n\tconstructor(config: PageAgentConfig) {\n\t\tsuper()\n\n\t\tthis.config = config\n\t\tthis.#llm = new LLM(this.config)\n\n\t\t// Conditionally initialize Panel\n\t\tif (this.config.enablePanel !== false) {\n\t\t\tthis.panel = new Panel({\n\t\t\t\tlanguage: this.config.language,\n\t\t\t\tonExecuteTask: (task) => this.execute(task),\n\t\t\t\tonStop: () => this.dispose(),\n\t\t\t\tpromptForNextTask: this.config.promptForNextTask,\n\t\t\t})\n\t\t}\n\n\t\tthis.tools = new Map(tools)\n\n\t\t// Initialize PageController with config (mask enabled by default)\n\t\tthis.pageController = new PageController({\n\t\t\t...this.config,\n\t\t\tenableMask: this.config.enableMask ?? true,\n\t\t})\n\n\t\t// Listen to LLM events\n\t\tthis.#llmRetryListener = (e) => {\n\t\t\tconst { current, max } = (e as CustomEvent).detail\n\t\t\tthis.panel?.update({ type: 'retry', current, max })\n\t\t}\n\t\tthis.#llmErrorListener = (e) => {\n\t\t\tconst { error } = (e as CustomEvent).detail\n\t\t\tthis.panel?.update({ type: 'error', message: `step failed: ${error.message}` })\n\t\t}\n\t\tthis.#llm.addEventListener('retry', this.#llmRetryListener)\n\t\tthis.#llm.addEventListener('error', this.#llmErrorListener)\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\n\t\t// Disable ask_user tool if enableAskUser is false or if panel is disabled\n\t\tif (this.config.enableAskUser === false || this.config.enablePanel === false) {\n\t\t\tthis.tools.delete('ask_user')\n\t\t}\n\n\t\tthis.#beforeUnloadListener = (e) => {\n\t\t\tif (!this.disposed) this.dispose('PAGE_UNLOADING')\n\t\t}\n\t\twindow.addEventListener('beforeunload', this.#beforeUnloadListener)\n\t}\n\n\t/**\n\t * Push a persistent observation to the history event stream.\n\t * This will be visible in <agent_history> and remain in memory across steps.\n\t */\n\tpushObservation(content: string): void {\n\t\tthis.history.push({ type: 'observation', content })\n\t\tthis.panel?.update({ type: 'observation', content })\n\t}\n\n\tasync execute(task: string): Promise<ExecutionResult> {\n\t\tif (!task) throw new Error('Task is required')\n\t\tthis.task = task\n\t\tthis.taskId = uid()\n\n\t\tconst onBeforeStep = this.config.onBeforeStep || (() => void 0)\n\t\tconst onAfterStep = this.config.onAfterStep || (() => void 0)\n\t\tconst onBeforeTask = this.config.onBeforeTask || (() => void 0)\n\t\tconst onAfterTask = this.config.onAfterTask || (() => void 0)\n\n\t\tawait onBeforeTask.call(this)\n\n\t\t// Show mask and panel\n\t\tthis.pageController.showMask()\n\n\t\tthis.panel?.show()\n\t\tthis.panel?.reset()\n\n\t\tthis.panel?.update({ type: 'input', task: this.task })\n\n\t\tif (this.#abortController) {\n\t\t\tthis.#abortController.abort()\n\t\t\tthis.#abortController = new AbortController()\n\t\t}\n\n\t\tthis.history = []\n\n\t\t// Reset states\n\t\tthis.states = {\n\t\t\ttotalWaitTime: 0,\n\t\t\tlastURL: '',\n\t\t}\n\n\t\ttry {\n\t\t\tlet step = 0\n\n\t\t\twhile (true) {\n\t\t\t\tawait this.#generateObservations(step)\n\n\t\t\t\tawait onBeforeStep.call(this, step)\n\n\t\t\t\tconsole.group(`step: ${step}`)\n\n\t\t\t\t// abort\n\t\t\t\tif (this.#abortController.signal.aborted) throw new Error('AbortError')\n\n\t\t\t\t// Update status to thinking\n\t\t\t\tconsole.log(chalk.blue('Thinking...'))\n\t\t\t\tthis.panel?.update({ type: 'thinking' })\n\n\t\t\t\tconst result = await this.#llm.invoke(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trole: 'system',\n\t\t\t\t\t\t\tcontent: this.#getSystemPrompt(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trole: 'user',\n\t\t\t\t\t\t\tcontent: await this.#assembleUserPrompt(),\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t{ AgentOutput: this.#packMacroTool() },\n\t\t\t\t\tthis.#abortController.signal,\n\t\t\t\t\t{\n\t\t\t\t\t\ttoolChoiceName: 'AgentOutput',\n\t\t\t\t\t\tnormalizeResponse,\n\t\t\t\t\t}\n\t\t\t\t)\n\n\t\t\t\tconst macroResult = result.toolResult as MacroToolResult\n\t\t\t\tconst input = macroResult.input\n\t\t\t\tconst output = macroResult.output\n\t\t\t\tconst reflection: Partial<AgentReflection> = {\n\t\t\t\t\tevaluation_previous_goal: input.evaluation_previous_goal,\n\t\t\t\t\tmemory: input.memory,\n\t\t\t\t\tnext_goal: input.next_goal,\n\t\t\t\t}\n\t\t\t\tconst actionName = Object.keys(input.action)[0]\n\t\t\t\tconst action: AgentStep['action'] = {\n\t\t\t\t\tname: actionName,\n\t\t\t\t\tinput: input.action[actionName],\n\t\t\t\t\toutput: output,\n\t\t\t\t}\n\n\t\t\t\tthis.history.push({\n\t\t\t\t\ttype: 'step',\n\t\t\t\t\treflection,\n\t\t\t\t\taction,\n\t\t\t\t\tusage: result.usage,\n\t\t\t\t} as AgentStep)\n\n\t\t\t\tconsole.log(chalk.green('Step finished:'), actionName)\n\t\t\t\tconsole.groupEnd()\n\n\t\t\t\tawait onAfterStep.call(this, step, this.history)\n\n\t\t\t\tstep++\n\t\t\t\tif (step > MAX_STEPS) {\n\t\t\t\t\tthis.#onDone('Step count exceeded maximum limit', false)\n\t\t\t\t\tconst result: ExecutionResult = {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tdata: 'Step count exceeded maximum limit',\n\t\t\t\t\t\thistory: this.history,\n\t\t\t\t\t}\n\t\t\t\t\tawait onAfterTask.call(this, result)\n\t\t\t\t\treturn result\n\t\t\t\t}\n\t\t\t\tif (actionName === 'done') {\n\t\t\t\t\tconst success = action.input?.success ?? false\n\t\t\t\t\tconst text = action.input?.text || 'no text provided'\n\t\t\t\t\tconsole.log(chalk.green.bold('Task completed'), success, text)\n\t\t\t\t\tthis.#onDone(text, success)\n\t\t\t\t\tconst result: ExecutionResult = {\n\t\t\t\t\t\tsuccess,\n\t\t\t\t\t\tdata: text,\n\t\t\t\t\t\thistory: this.history,\n\t\t\t\t\t}\n\t\t\t\t\tawait onAfterTask.call(this, result)\n\t\t\t\t\treturn result\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tconsole.error('Task failed', error)\n\t\t\tthis.#onDone(String(error), false)\n\t\t\tconst result: ExecutionResult = {\n\t\t\t\tsuccess: false,\n\t\t\t\tdata: String(error),\n\t\t\t\thistory: this.history,\n\t\t\t}\n\t\t\tawait onAfterTask.call(this, result)\n\t\t\treturn result\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 zod.object({ [toolName]: tool.inputSchema }).describe(tool.description)\n\t\t})\n\n\t\tconst actionSchema = zod.union(\n\t\t\tactionSchemas as unknown as [zod.ZodType, zod.ZodType, ...zod.ZodType[]]\n\t\t)\n\n\t\tconst macroToolSchema = zod.object({\n\t\t\t// thinking: zod.string().optional(),\n\t\t\tevaluation_previous_goal: zod.string().optional(),\n\t\t\tmemory: zod.string().optional(),\n\t\t\tnext_goal: zod.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. Outputs your reflections and next action.',\n\t\t\tinputSchema: macroToolSchema as zod.ZodType<MacroToolInput>,\n\t\t\texecute: async (input: MacroToolInput): Promise<MacroToolResult> => {\n\t\t\t\t// abort\n\t\t\t\tif (this.#abortController.signal.aborted) throw new Error('AbortError')\n\n\t\t\t\tconsole.log(chalk.blue.bold('MacroTool execute'), 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\tthis.panel?.update({ type: 'thinking', text: 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. (@note should have been caught before this!!!)`)\n\n\t\t\t\tconsole.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput)\n\t\t\t\tthis.panel?.update({ type: 'toolExecuting', toolName, args: toolInput })\n\n\t\t\t\tconst startTime = Date.now()\n\n\t\t\t\t// Execute tool, bind `this` to PageAgent\n\t\t\t\tconst result = await tool.execute.bind(this)(toolInput)\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// Reset wait time for non-wait tools\n\t\t\t\tif (toolName !== 'wait') {\n\t\t\t\t\tthis.states.totalWaitTime = 0\n\t\t\t\t}\n\n\t\t\t\t// Briefly display execution result\n\t\t\t\tthis.panel?.update({\n\t\t\t\t\ttype: 'toolCompleted',\n\t\t\t\t\ttoolName,\n\t\t\t\t\targs: toolInput,\n\t\t\t\t\tresult,\n\t\t\t\t\tduration,\n\t\t\t\t})\n\n\t\t\t\t// Wait a moment to let user see the result\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 100))\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\tlet systemPrompt = SYSTEM_PROMPT\n\n\t\tconst targetLanguage = this.config.language === 'zh-CN' ? '中文' : 'English'\n\t\tsystemPrompt = systemPrompt.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 and format as XML block\n\t */\n\tasync #getInstructions(): Promise<string> {\n\t\tconst { instructions } = this.config\n\t\tif (!instructions) return ''\n\n\t\tconst systemInstructions = instructions.system?.trim()\n\t\tconst url = await this.pageController.getCurrentUrl()\n\t\tlet pageInstructions: string | undefined\n\n\t\tif (instructions.getPageInstructions) {\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\t\tif (!systemInstructions && !pageInstructions) 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\tresult += '</instructions>\\n\\n'\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Generate observations before each step\n\t * - URL change detection\n\t * - Too many steps warning\n\t * @todo loop detection\n\t * @todo console error\n\t */\n\tasync #generateObservations(stepCount: number): Promise<void> {\n\t\t// Detect URL change\n\t\tconst currentURL = await this.pageController.getCurrentUrl()\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}\n\n\t\t// Warn about remaining steps\n\t\tconst remaining = MAX_STEPS - stepCount\n\t\tif (remaining === 5) {\n\t\t\tthis.pushObservation(\n\t\t\t\t`⚠️ Only ${remaining} steps remaining. 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\t}\n\n\tasync #assembleUserPrompt(): Promise<string> {\n\t\tlet prompt = ''\n\n\t\t// <instructions> (optional)\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\t\t\t<user_request>\n\t\t\t${this.task}\n\t\t\t</user_request>\n\t\t\t<step_info>\n\t\t\tStep ${stepCount + 1} of ${MAX_STEPS} max possible steps\n\t\t\tCurrent date and time: ${new Date().toISOString()}\n\t\t\t</step_info>\n\t\t\t</agent_state>\n\t\t`\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 += '\\n<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\t\t\t\tEvaluation of Previous Step: ${event.reflection.evaluation_previous_goal}\n\t\t\t\tMemory: ${event.reflection.memory}\n\t\t\t\tNext Goal: ${event.reflection.next_goal}\n\t\t\t\tAction Results: ${event.action.output}\n\t\t\t\t</step_${stepIndex}>\n\t\t\t`\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}\n\t\t}\n\n\t\tprompt += '</agent_history>\\n\\n'\n\n\t\t// <browser_state>\n\n\t\tprompt += await this.#getBrowserState()\n\n\t\treturn trimLines(prompt)\n\t}\n\n\t#onDone(text: string, success = true) {\n\t\tthis.pageController.cleanUpHighlights()\n\n\t\t// Update panel status\n\t\tif (success) {\n\t\t\tthis.panel?.update({ type: 'output', text })\n\t\t} else {\n\t\t\tthis.panel?.update({ type: 'error', message: text })\n\t\t}\n\n\t\t// Task completed\n\t\tthis.panel?.update({ type: 'completed' })\n\n\t\tthis.pageController.hideMask()\n\n\t\tthis.#abortController.abort()\n\t}\n\n\tasync #getBrowserState(): Promise<string> {\n\t\tconst state = await this.pageController.getBrowserState()\n\n\t\tlet content = state.content\n\t\tif (this.config.transformPageContent) {\n\t\t\tcontent = await this.config.transformPageContent(content)\n\t\t}\n\n\t\treturn trimLines(`<browser_state>\n\t\t\tCurrent Page: [${state.title}](${state.url})\n\n\t\t\t${state.header}\n\t\t\t${content}\n\t\t\t${state.footer}\n\n\t\t\t</browser_state>\n\t\t`)\n\t}\n\n\tdispose(reason?: string) {\n\t\tconsole.log('Disposing PageAgent...')\n\t\tthis.disposed = true\n\t\tthis.pageController.dispose()\n\t\tthis.panel?.dispose()\n\t\tthis.history = []\n\t\tthis.#abortController.abort(reason ?? 'PageAgent disposed')\n\n\t\t// Clean up LLM event listeners\n\t\tif (this.#llmRetryListener) {\n\t\t\tthis.#llm.removeEventListener('retry', this.#llmRetryListener)\n\t\t\tthis.#llmRetryListener = null\n\t\t}\n\t\tif (this.#llmErrorListener) {\n\t\t\tthis.#llm.removeEventListener('error', this.#llmErrorListener)\n\t\t\tthis.#llmErrorListener = null\n\t\t}\n\n\t\t// Clean up window event listeners\n\t\tif (this.#beforeUnloadListener) {\n\t\t\twindow.removeEventListener('beforeunload', this.#beforeUnloadListener)\n\t\t\tthis.#beforeUnloadListener = null\n\t\t}\n\n\t\tthis.config.onDispose?.call(this, reason)\n\t}\n}\n"],"names":["tool","result","tools"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "page-agent",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/esm/page-agent.js",
|
|
7
7
|
"module": "./dist/esm/page-agent.js",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"chalk": "^5.6.2",
|
|
47
47
|
"zod": "^4.3.5",
|
|
48
|
-
"@page-agent/llms": "0.2.
|
|
49
|
-
"@page-agent/page-controller": "0.2.
|
|
50
|
-
"@page-agent/ui": "0.2.
|
|
48
|
+
"@page-agent/llms": "0.2.5",
|
|
49
|
+
"@page-agent/page-controller": "0.2.5",
|
|
50
|
+
"@page-agent/ui": "0.2.5"
|
|
51
51
|
}
|
|
52
52
|
}
|