play-ai
Version:
Automate Playwright tests using OpenAI integration
1 lines • 53.2 kB
Source Map (JSON)
{"version":3,"sources":["../src/ai/config.ts","../src/ai/completeTask.ts","../src/ai/prompt.ts","../src/ai/createActions.ts","../src/ai/sanitizedHtml.ts","../src/ai/getSnapshot.ts","../src/ai/errors.ts","../src/ai/play.ts"],"sourcesContent":["const char_count = process.env.MAX_TASK_CHARS || \"2000\";\n/**\n * Retrieves the maximum number of characters allowed for a task from the environment variable `MAX_TASK_CHARS`.\n * If the environment variable is not set, it defaults to \"2000\".\n *\n * This constant is used to ensure that tasks do not exceed a specified character limit, which can be important for\n * maintaining performance and avoiding issues with excessively large tasks.\n *\n * @constant\n * @type {number}\n * @default 2000\n * @example\n * ```typescript\n * import { MAX_TASK_CHARS } from \"./config\";\n * \n * console.log(MAX_TASK_CHARS); // Outputs the maximum number of characters allowed for a task, e.g., 2000\n * ```\n */\nexport const MAX_TASK_CHARS = parseInt(char_count, 10);\n","import OpenAI from \"openai\";\nimport { type Page, TaskMessage, TaskResult } from \"./types\";\nimport { prompt } from \"./prompt\";\nimport { createActions } from \"./createActions\";\n\nconst defaultDebug = process.env.PLAY_AI_DEBUG === \"true\";\n\n/**\n * Completes a task using OpenAI's API and Playwright.\n *\n * This function integrates OpenAI's API with Playwright to complete a given task. It sends a prompt to OpenAI, executes the\n * actions on the Playwright `page`, and returns the result of the task execution.\n *\n * @param page - The Playwright `Page` object where the task will be executed.\n * @param task - The task message containing task details and options.\n * @returns A promise that resolves to the task result.\n * @throws Will throw an error if no function result is found.\n *\n * @example\n * ```typescript\n * import { completeTask } from \"./completeTask\";\n * import { Page } from \"playwright\";\n *\n * const page: Page = ...; // Initialize Playwright page\n * const taskMessage = {\n * task: \"Type 'standard_user' in the Username field\",\n * options: {\n * openaiApiKey: \"sk-...\",\n * model: \"gpt-4o\",\n * debug: true,\n * },\n * };\n *\n * const result = await completeTask(page, taskMessage);\n * console.log(result); // Logs the result of the task execution\n * ```\n */\nexport const completeTask = async (\n page: Page,\n task: TaskMessage\n): Promise<TaskResult> => {\n const openai = new OpenAI({\n apiKey: task.options?.openaiApiKey,\n baseURL: task.options?.openaiBaseUrl,\n defaultQuery: task.options?.openaiDefaultQuery,\n defaultHeaders: task.options?.openaiDefaultHeaders,\n });\n\n let lastFunctionResult: null | { errorMessage: string } | { query: string } =\n null;\n\n const actions = createActions(page);\n\n const debug = task.options?.debug ?? defaultDebug;\n\n const runner = openai.beta.chat.completions\n .runTools({\n model: task.options?.model ?? \"gpt-4o\",\n messages: [\n {\n role: \"user\",\n content: prompt(task),\n },\n ],\n tools: Object.values(actions).map((action) => ({\n type: \"function\",\n function: action,\n })),\n })\n .on(\"message\", (message) => {\n if (debug) {\n console.log(\"> Message\", message);\n }\n\n if (\n message.role === \"assistant\" &&\n message.tool_calls &&\n message.tool_calls.length > 0 &&\n message.tool_calls[0].function.arguments\n ) {\n lastFunctionResult = JSON.parse(\n message.tool_calls[0].function.arguments\n );\n }\n });\n\n const finalContent = await runner.finalContent();\n\n if (debug) {\n console.log(\"> finalContent\", finalContent);\n }\n\n if (!lastFunctionResult) {\n throw new Error(\"No function result found.\");\n }\n\n if (debug) {\n console.log(\"> lastFunctionResult\", lastFunctionResult);\n }\n\n return lastFunctionResult;\n};\n","import { TaskMessage } from \"./types\";\n\n/**\n * Generates a prompt for OpenAI based on the provided task message.\n *\n * This function creates a formatted prompt string that includes the task description and guidelines for creating CSS selectors.\n * It also includes a snapshot of the current state of the webpage.\n *\n * @param {TaskMessage} message - The task message containing the task details and the webpage snapshot.\n * @returns {string} The formatted prompt string to be sent to OpenAI.\n *\n * @example\n * ```typescript\n * import { prompt } from \"./prompt\";\n * import { TaskMessage } from \"./types\";\n *\n * const taskMessage: TaskMessage = {\n * task: \"Type 'standard_user' in the Username field\",\n * snapshot: {\n * dom: \"<html>...</html>\",\n * },\n * options: {\n * openaiApiKey: \"sk-...\",\n * model: \"gpt-4o\",\n * debug: true,\n * },\n * };\n *\n * const promptString = prompt(taskMessage);\n * console.log(promptString);\n * ```\n */\nexport const prompt = (message: TaskMessage): string => {\n return `This is your task: ${message.task}\n\n* When creating CSS selectors, ensure they are unique and specific enough to select only one element, even if there are multiple elements of the same type (like multiple h1 elements).\n* Avoid using generic tags like 'h1' alone. Instead, combine them with other attributes or structural relationships to form a unique selector.\n* You must not derive data from the page if you are able to do so by using one of the provided functions, e.g. locator_evaluate.\n\nWebpage snapshot:\n\n\\`\\`\\`\n${message.snapshot.dom}\n\\`\\`\\`\n`;\n};\n","import { Locator, Page } from \"@playwright/test\";\nimport { randomUUID } from \"crypto\";\nimport { RunnableFunctionWithParse } from \"openai/lib/RunnableFunction\";\nimport { z } from \"zod\";\n\n/**\n * Creates a set of actions that can be performed on a Playwright `page`.\n *\n * This function generates a record of actions that can be executed on a Playwright `page`. Each action is represented as a\n * `RunnableFunctionWithParse` object, which includes the function to be executed, a description, and a schema for parsing\n * the function's arguments.\n *\n * @param {Page} page - The Playwright `page` object where the actions will be performed.\n * @returns {Record<string, RunnableFunctionWithParse<any>>} - A record of actions that can be performed on the page.\n */\nexport const createActions = (\n page: Page\n): Record<string, RunnableFunctionWithParse<any>> => {\n const locatorMap = new Map();\n\n /**\n * Retrieves a locator from the locator map using the provided element ID.\n *\n * @param {string} elementId - The ID of the element to locate.\n * @returns {Locator} - The Playwright `Locator` object for the specified element.\n * @throws {Error} - Throws an error if the element ID is not found in the locator map.\n */\n const getLocator = (elementId: string): Locator => {\n console.log(\"locatorMap\", locatorMap);\n const locator: Locator = locatorMap.get(elementId);\n\n if (!locator) {\n throw new Error('Unknown elementId \"' + elementId + '\"');\n }\n\n return locator;\n };\n\n /**\n * Scrolls the page to bring the specified element into view.\n *\n * @param {Locator} locator - The Playwright `Locator` object for the element to scroll into view.\n * @returns {Promise<void>}\n */\n const scrollIntoView = async (locator: Locator) => {\n let i = 0;\n while (await locator.isHidden()) {\n //await this.page.locator(\"your locator goes here\").click();\n await page.mouse.wheel(0, 300);\n i++;\n if (await locator.isVisible()) {\n return;\n } else if (i >= 5) {\n return;\n }\n }\n };\n\n /**\n * Waits for the page to load completely.\n *\n * @returns {Promise<void>}\n */\n const waitForPageLoad = async () => {\n await page.waitForLoadState(\"domcontentloaded\", { timeout: 30000 });\n };\n\n return {\n locateElement: {\n function: async (args: { cssSelector: string }) => {\n const locator: Locator = await page.locator(args.cssSelector);\n\n const elementId = randomUUID();\n\n locatorMap.set(elementId, locator);\n\n return {\n elementId,\n };\n },\n name: \"locateElement\",\n description:\n \"Locates element using a CSS selector and returns elementId. This element ID can be used with other functions to perform actions on the element.\",\n parse: (args: string) => {\n return z\n .object({\n cssSelector: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n cssSelector: {\n type: \"string\",\n },\n },\n },\n },\n locator_evaluate: {\n function: async (args: { pageFunction: string; elementId: string }) => {\n return {\n result: await getLocator(args.elementId).evaluate(args.pageFunction),\n };\n },\n description:\n \"Execute JavaScript code in the page, taking the matching element as an argument.\",\n name: \"locator_evaluate\",\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n pageFunction: {\n type: \"string\",\n description:\n \"Function to be evaluated in the page context, e.g. node => node.innerText\",\n },\n },\n },\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n pageFunction: z.string(),\n })\n .parse(JSON.parse(args));\n },\n },\n locator_getAttribute: {\n function: async (args: { attributeName: string; elementId: string }) => {\n return {\n attributeValue: await getLocator(args.elementId).getAttribute(\n args.attributeName\n ),\n };\n },\n name: \"locator_getAttribute\",\n description: \"Returns the matching element's attribute value.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n attributeName: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n attributeName: {\n type: \"string\",\n },\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_innerHTML: {\n function: async (args: { elementId: string }) => {\n return { innerHTML: await getLocator(args.elementId).innerHTML() };\n },\n name: \"locator_innerHTML\",\n description: \"Returns the element.innerHTML.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_innerText: {\n function: async (args: { elementId: string }) => {\n return { innerText: await getLocator(args.elementId).innerText() };\n },\n name: \"locator_innerText\",\n description: \"Returns the element.innerText.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_textContent: {\n function: async (args: { elementId: string }) => {\n return {\n textContent: await getLocator(args.elementId).textContent(),\n };\n },\n name: \"locator_textContent\",\n description: \"Returns the node.textContent.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_inputValue: {\n function: async (args: { elementId: string }) => {\n return {\n inputValue: await getLocator(args.elementId).inputValue(),\n };\n },\n name: \"locator_inputValue\",\n description:\n \"Returns input.value for the selected <input> or <textarea> or <select> element.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_blur: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).blur();\n\n return { success: true };\n },\n name: \"locator_blur\",\n description: \"Removes keyboard focus from the current element.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_boundingBox: {\n function: async (args: { elementId: string }) => {\n return await getLocator(args.elementId).boundingBox();\n },\n name: \"locator_boundingBox\",\n description:\n \"This method returns the bounding box of the element matching the locator, or null if the element is not visible. The bounding box is calculated relative to the main frame viewport - which is usually the same as the browser window. The returned object has x, y, width, and height properties.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_check: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).check();\n\n return { success: true };\n },\n name: \"locator_check\",\n description: \"Ensure that checkbox or radio element is checked.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_uncheck: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).uncheck();\n\n return { success: true };\n },\n name: \"locator_uncheck\",\n description: \"Ensure that checkbox or radio element is unchecked.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_isChecked: {\n function: async (args: { elementId: string }) => {\n return { isChecked: await getLocator(args.elementId).isChecked() };\n },\n name: \"locator_isChecked\",\n description: \"Returns whether the element is checked.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_isEditable: {\n function: async (args: { elementId: string }) => {\n return {\n isEditable: await getLocator(args.elementId).isEditable(),\n };\n },\n name: \"locator_isEditable\",\n description:\n \"Returns whether the element is editable. Element is considered editable when it is enabled and does not have readonly property set.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_isEnabled: {\n function: async (args: { elementId: string }) => {\n return { isEnabled: await getLocator(args.elementId).isEnabled() };\n },\n name: \"locator_isEnabled\",\n description:\n \"Returns whether the element is enabled. Element is considered enabled unless it is a <button>, <select>, <input> or <textarea> with a disabled property.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_isVisible: {\n function: async (args: { elementId: string }) => {\n return { isVisible: await getLocator(args.elementId).isVisible() };\n },\n name: \"locator_isVisible\",\n description: \"Returns whether the element is visible.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_clear: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).clear();\n\n return { success: true };\n },\n name: \"locator_clear\",\n description: \"Clear the input field.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_click: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).click();\n\n return { success: true };\n },\n name: \"locator_click\",\n description: \"Click an element.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_dbl_click: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).dblclick();\n\n return { success: true };\n },\n name: \"locator_dbl_click\",\n description: \"Double Click an element.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_count: {\n function: async (args: { elementId: string }) => {\n return { elementCount: await getLocator(args.elementId).count() };\n },\n name: \"locator_count\",\n description: \"Returns the number of elements matching the locator.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_fill: {\n function: async (args: { value: string; elementId: string }) => {\n await getLocator(args.elementId).fill(args.value);\n\n return {\n success: true,\n };\n },\n name: \"locator_fill\",\n description: \"Set a value to the input field.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n value: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n value: {\n type: \"string\",\n },\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_hover: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).hover();\n\n return {\n success: true,\n };\n },\n name: \"locator_hover\",\n description: \"Hover on an element.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_scroll_into_view_if_needed: {\n function: async (args: { elementId: string }) => {\n await getLocator(args.elementId).scrollIntoViewIfNeeded();\n\n return { success: true };\n },\n name: \"locator_scroll_into_view_if_needed\",\n description: \"Scroll into view an element if needed.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_scroll_into_element_view: {\n function: async (args: { elementId: string }) => {\n await scrollIntoView(getLocator(args.elementId));\n\n return { success: true };\n },\n name: \"locator_scroll_into_element_view\",\n description: \"Scroll into view an element.\",\n parse: (args: string) => {\n return z\n .object({\n elementId: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n elementId: {\n type: \"string\",\n },\n },\n },\n },\n locator_wait_for_page_load: {\n function: async () => {\n await waitForPageLoad();\n\n return { success: true };\n },\n name: \"locator_wait_for_page_load\",\n description: \"Wait until page load completely\",\n parse: (args: string) => {\n return z.object({}).parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {},\n },\n },\n page_goto: {\n function: async (args: { url: string }) => {\n return {\n url: await page.goto(args.url),\n };\n },\n name: \"page_goto\",\n description: \"Set a value to the input field.\",\n parse: (args: string) => {\n return z\n .object({\n cssLocator: z.string(),\n value: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n value: {\n type: \"string\",\n },\n cssLocator: {\n type: \"string\",\n },\n },\n },\n },\n expect_toBe: {\n function: (args: { actual: string; expected: string }) => {\n return {\n actual: args.actual,\n expected: args.expected,\n success: args.actual === args.expected,\n };\n },\n name: \"expect_toBe\",\n description:\n \"Asserts that the actual value is equal to the expected value.\",\n parse: (args: string) => {\n return z\n .object({\n actual: z.string(),\n expected: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n actual: {\n type: \"string\",\n },\n expected: {\n type: \"string\",\n },\n },\n },\n },\n expect_notToBe: {\n function: (args: { actual: string; expected: string }) => {\n return {\n actual: args.actual,\n expected: args.expected,\n success: args.actual !== args.expected,\n };\n },\n name: \"expect_notToBe\",\n description:\n \"Asserts that the actual value is not equal to the expected value.\",\n parse: (args: string) => {\n return z\n .object({\n actual: z.string(),\n expected: z.string(),\n })\n .parse(JSON.parse(args));\n },\n parameters: {\n type: \"object\",\n properties: {\n actual: {\n type: \"string\",\n },\n expected: {\n type: \"string\",\n },\n },\n },\n },\n resultAssertion: {\n function: (args: { assertion: boolean }) => {\n return args;\n },\n parse: (args: string) => {\n return z\n .object({\n assertion: z.boolean(),\n })\n .parse(JSON.parse(args));\n },\n description:\n \"This function is called when the initial instructions asked to assert something; then 'assertion' is either true or false (boolean) depending on whether the assertion succeeded.\",\n name: \"resultAssertion\",\n parameters: {\n type: \"object\",\n properties: {\n assertion: {\n type: \"boolean\",\n },\n },\n },\n },\n resultQuery: {\n function: (args: { assertion: boolean }) => {\n return args;\n },\n parse: (args: string) => {\n return z\n .object({\n query: z.string(),\n })\n .parse(JSON.parse(args));\n },\n description:\n \"This function is called at the end when the initial instructions asked to extract data; then 'query' property is set to a text value of the extracted data.\",\n name: \"resultQuery\",\n parameters: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n },\n },\n },\n },\n resultAction: {\n function: () => {\n return null;\n },\n parse: (args: string) => {\n return z.object({}).parse(JSON.parse(args));\n },\n description:\n \"This function is called at the end when the initial instructions asked to perform an action.\",\n name: \"resultAction\",\n parameters: {\n type: \"object\",\n properties: {},\n },\n },\n resultError: {\n function: (args: { errorMessage: string }) => {\n return {\n errorMessage: args.errorMessage,\n };\n },\n parse: (args: string) => {\n return z\n .object({\n errorMessage: z.string(),\n })\n .parse(JSON.parse(args));\n },\n description:\n \"If user instructions cannot be completed, then this function is used to produce the final response.\",\n name: \"resultError\",\n parameters: {\n type: \"object\",\n properties: {\n errorMessage: {\n type: \"string\",\n },\n },\n },\n },\n };\n};\n","import sanitizeHtml from \"sanitize-html\";\n\n/**\n * Sanitizes an HTML string by allowing only a specific set of tags and attributes.\n *\n * This function uses the `sanitize-html` library to clean an HTML string, ensuring that only a predefined set of tags and attributes\n * are allowed. This helps prevent XSS (Cross-Site Scripting) attacks by removing potentially harmful content.\n *\n * @param {string} subject - The HTML string to be sanitized.\n * @returns {string} - The sanitized HTML string.\n *\n * @example\n * ```typescript\n * const dirtyHtml = '<div><script>alert(\"xss\")</script><button>Click me</button></div>';\n * const cleanHtml = sanitizeHtmlString(dirtyHtml);\n * console.log(cleanHtml); // Output: '<div><button>Click me</button></div>'\n * ```\n */\nexport const sanitizeHtmlString = (subject: string): string => {\n return sanitizeHtml(subject, {\n allowedTags: sanitizeHtml.defaults.allowedTags.concat([\n \"button\",\n \"input\",\n \"select\",\n \"option\",\n \"textarea\",\n \"form\",\n \"img\",\n \"label\",\n \"span\",\n ]),\n allowedAttributes: false,\n });\n};\n","import { sanitizeHtmlString } from \"./sanitizedHtml\";\nimport { Page } from \"./types\";\n\n/**\n * Captures a snapshot of the current state of the Playwright `page`.\n *\n * This function retrieves the HTML content of the provided `page`, sanitizes it to remove any potentially harmful content, \n * and returns an object containing the sanitized DOM string.\n *\n * @param page - The Playwright `page` object from which the snapshot will be taken.\n * @returns A promise that resolves to an object containing the sanitized DOM string.\n *\n * @example\n * ```typescript\n * import { getSnapshot } from \"./getSnapshot\";\n * import { Page } from \"playwright\";\n *\n * const snapshot = await getSnapshot(page);\n * console.log(snapshot.dom); // Logs the sanitized HTML content of the page\n * ```\n */\nexport const getSnapshot = async (page: Page) => {\n return {\n dom: sanitizeHtmlString(await page.content()),\n };\n};\n","/**\n * Base class for all custom errors in the Play AI framework.\n *\n * This abstract class serves as the base for all custom error types in the Play AI framework. It extends the built-in `Error` class\n * and provides a consistent structure for error handling within the framework.\n *\n * @export\n * @abstract\n * @class PlayAIError\n * @extends {Error}\n */\nexport abstract class PlayAIError extends Error {\n /**\n * Creates an instance of PlayAIError.\n *\n * @param {string} [message] - The error message.\n */\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\n/**\n * Error class for unimplemented features in the Play AI framework.\n *\n * This class represents an error that is thrown when a feature is not yet implemented in the Play AI framework. It extends the\n * `PlayAIError` class and provides a default error message.\n *\n * @export\n * @class UnimplementedError\n * @extends {PlayAIError}\n */\nexport class UnimplementedError extends PlayAIError {\n /**\n * Creates an instance of UnimplementedError.\n *\n * @param {string} [message] - The error message. If not provided, a default message \"This feature is not yet implemented.\" is used.\n */\n public constructor(message?: string) {\n super(message || \"This feature is not yet implemented.\");\n }\n}\n","import { MAX_TASK_CHARS } from \"./config\";\nimport { type Page, type Test, StepOptions } from \"./types\";\nimport { completeTask } from \"./completeTask\";\nimport { getSnapshot } from \"./getSnapshot\";\nimport { UnimplementedError } from \"./errors\";\n\n/**\n * Executes a task or a series of tasks using Playwright and OpenAI integration.\n *\n * This function allows you to execute a single task or an array of tasks on a Playwright `page` using OpenAI's capabilities.\n * It can be used within a Playwright test context to perform automated actions and assertions.\n *\n * @param task - A single task or an array of tasks to be executed. Each task is a string describing the action to be performed.\n * @param config - Configuration object containing the Playwright `page` and optional `test` context.\n * @param config.page - The Playwright `page` object where the tasks will be executed.\n * @param config.test - Optional Playwright `test` context for running the tasks within a test step.\n * @param options - Optional configuration for the task execution, including OpenAI settings.\n * @param options.model - The OpenAI model to be used for task execution (default is \"gpt-4o\").\n * @param options.debug - Boolean flag to enable debugging mode (default is false).\n * @param options.openaiApiKey - The API key for accessing OpenAI services.\n * @param options.openaiBaseUrl - The base URL for OpenAI API requests.\n * @param options.openaiDefaultQuery - Default query parameters for OpenAI requests.\n * @param options.openaiDefaultHeaders - Default headers for OpenAI requests.\n * @returns A promise that resolves with the result of the task execution. The result can include assertions, queries, or other outputs.\n * @throws {UnimplementedError} If the required `page` argument is missing in the config.\n * @throws {Error} If the task length exceeds the maximum allowed characters.\n *\n * @example\n * ```typescript\n * import { play } from \"./play\";\n * import { Page, Test } from \"playwright\";\n *\n * const page: Page = ...; // Initialize Playwright page\n * const test: Test = ...; // Initialize Playwright test context\n *\n * await play(\"Type 'standard_user' in the Username field\", { page, test });\n * await play(\"Click the Login button\", { page, test });\n * ```\n */\nexport const play = async (\n task: string | string[],\n config: { page: Page; test: Test },\n options?: StepOptions\n): Promise<any> => {\n if (!config || !config.page) {\n throw new UnimplementedError(\n \"The play() function is missing the required `{ page }` argument.\"\n );\n }\n\n const { test, page } = config as { test?: Test; page: Page };\n\n if (!test) {\n return await runTask(task, page, options);\n }\n\n return test.step(`play-ai '${task}'`, async () => {\n const result = await runTask(task, page, options);\n\n if (result.errorMessage) {\n throw new UnimplementedError(result.errorMessage);\n }\n\n if (result.assertion !== undefined) {\n return result.assertion;\n }\n\n if (result.query) {\n return result.query;\n }\n return undefined;\n });\n};\n\n/**\n * Runs a task or a series of tasks on the provided Playwright `page`.\n *\n * This helper function is responsible for executing the given tasks on the Playwright `page`. It handles the task execution\n * logic, including checking the task length and calling the `completeTask` function with the necessary parameters.\n *\n * @param task - A single task or an array of tasks to be executed. Each task is a string describing the action to be performed.\n * @param page - The Playwright `page` object where the tasks will be executed.\n * @param options - Optional configuration for the task execution, including OpenAI settings.\n * @returns A promise that resolves with the result of the task execution. The result can include assertions, queries, or other outputs.\n * @throws {Error} If the task length exceeds the maximum allowed characters.\n *\n * @example\n * ```typescript\n * import { runTask } from \"./play\";\n * import { Page } from \"playwright\";\n *\n * const page: Page = ...; // Initialize Playwright page\n *\n * const result = await runTask(\"Type 'standard_user' in the Username field\", page, { debug: true });\n * console.log(result); // Logs the result of the task execution\n * ```\n */\nasync function runTask(\n task: string | string[],\n page: Page,\n options: StepOptions | undefined\n) {\n if (task.length > MAX_TASK_CHARS) {\n throw new Error(\n `The task is too long. The maximum number of characters is ${MAX_TASK_CHARS}.`\n );\n }\n\n const result = await completeTask(page, {\n task,\n snapshot: await getSnapshot(page),\n options: options\n ? {\n model: options.model ?? \"gpt-4o\",\n debug: options.debug ?? false,\n openaiApiKey: options.openaiApiKey,\n openaiBaseUrl: options.openaiBaseUrl,\n openaiDefaultQuery: options.openaiDefaultQuery,\n openaiDefaultHeaders: options.openaiDefaultHeaders,\n }\n : undefined,\n });\n return result;\n}\n"],"mappings":"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