@stablyai/playwright-base 2.0.0-next.1 → 2.0.0

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/index.cjs CHANGED
@@ -71,11 +71,11 @@ var isObject = (value) => {
71
71
  // src/ai/metadata.ts
72
72
  var SDK_METADATA_HEADERS = {
73
73
  "X-Client-Name": "stably-playwright-sdk-js",
74
- "X-Client-Version": "2.0.0-next.1"
74
+ "X-Client-Version": "2.0.0"
75
75
  };
76
76
 
77
77
  // src/ai/verify-prompt.ts
78
- var PROMPT_ASSERTION_PATH = "internal/v1/assert";
78
+ var PROMPT_ASSERTION_PATH = "internal/v2/assert";
79
79
  var STABLY_API_URL = process.env.STABLY_API_URL || "https://api.stably.ai";
80
80
  var PROMPT_ASSERTION_ENDPOINT = new URL(
81
81
  PROMPT_ASSERTION_PATH,
@@ -105,15 +105,21 @@ var parseErrorResponse = (value) => {
105
105
  return typeof error !== "string" ? void 0 : { error };
106
106
  };
107
107
  async function verifyPrompt({
108
+ pageMetadata,
108
109
  prompt,
109
110
  screenshot
110
111
  }) {
111
112
  const apiKey = requireApiKey();
112
113
  const form = new FormData();
113
- form.append("prompt", prompt);
114
+ const metadata = {
115
+ prompt,
116
+ ...pageMetadata?.title ? { pageTitle: pageMetadata.title } : {},
117
+ ...pageMetadata?.url ? { pageUrl: pageMetadata.url } : {}
118
+ };
119
+ form.append("metadata", JSON.stringify(metadata));
114
120
  const u8 = Uint8Array.from(screenshot);
115
121
  const blob = new Blob([u8], { type: "image/png" });
116
- form.append("image", blob, "screenshot.png");
122
+ form.append("screenshot", blob, "screenshot.png");
117
123
  const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {
118
124
  body: form,
119
125
  headers: {
@@ -422,7 +428,11 @@ var stablyPlaywrightMatchers = {
422
428
  }
423
429
  const targetType = isPage(target) ? "page" : "locator";
424
430
  const screenshot = await takeStableScreenshot(target, options);
425
- const verifyResult = await verifyPrompt({ prompt: condition, screenshot });
431
+ const verifyResult = await verifyPrompt({
432
+ pageMetadata: isPage(target) ? { title: await target.title(), url: target.url() } : void 0,
433
+ prompt: condition,
434
+ screenshot
435
+ });
426
436
  const testInfo = import_test.test.info();
427
437
  testInfo.attachments.push({
428
438
  body: Buffer.from(
@@ -650,6 +660,7 @@ ${ariaSnapshot}` }
650
660
  const { reason, success } = agentResponse;
651
661
  return {
652
662
  activePage,
663
+ failureReason: success ? void 0 : reason,
653
664
  finalSuccess: success,
654
665
  result: { message: reason, shouldTerminate: true }
655
666
  };
@@ -678,7 +689,8 @@ var Agent = class {
678
689
  *
679
690
  * @param prompt - Natural language instruction describing what the agent should do
680
691
  * @param options - Configuration for the agent's behavior including the page to operate on
681
- * @returns Promise that resolves with the result of the agent's actions
692
+ * @returns Promise that resolves when the agent successfully completes the task
693
+ * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
682
694
  *
683
695
  * @example
684
696
  * ```typescript
@@ -689,14 +701,18 @@ var Agent = class {
689
701
  * await agent.act('Navigate to settings, enable notifications, and save changes', { page });
690
702
  *
691
703
  * // With custom options
692
- * const result = await agent.act('Complete the checkout process', {
704
+ * await agent.act('Complete the checkout process', {
693
705
  * page,
694
706
  * maxCycles: 20,
695
707
  * model: 'gpt-4'
696
708
  * });
697
709
  *
698
- * if (result.success) {
710
+ * // Handling failures with try-catch
711
+ * try {
712
+ * await agent.act('Complete the task', { page });
699
713
  * console.log('Agent completed the task successfully');
714
+ * } catch (error) {
715
+ * console.error('Agent failed:', error.message);
700
716
  * }
701
717
  * ```
702
718
  */
@@ -714,6 +730,7 @@ var Agent = class {
714
730
  shouldTerminate: false
715
731
  };
716
732
  let finalSuccess;
733
+ let failureReason;
717
734
  let newPageOpenedMsg;
718
735
  const sessionId = crypto.randomUUID();
719
736
  const onNewPage = async (page) => {
@@ -760,16 +777,18 @@ var Agent = class {
760
777
  `Agent call failed: ${JSON.stringify(responseJson)}`
761
778
  );
762
779
  }
763
- const reasoningTexts = responseJson.map((r) => r.content).filter((content) => content !== void 0);
780
+ const reasoningTexts = responseJson.map((r) => r.content?.trim()).filter((content) => content !== void 0);
764
781
  const reasoningText = reasoningTexts.join("\n\n");
765
- const truncatedReasoningText = truncate(reasoningText, 120);
766
- await stepInfo.attach(
767
- `[Thinking ${i + 1}] ${truncatedReasoningText}`,
768
- {
769
- body: reasoningText,
770
- contentType: "text/plain"
771
- }
772
- );
782
+ if (reasoningText) {
783
+ const truncatedReasoningText = truncate(reasoningText, 120);
784
+ await stepInfo.attach(
785
+ `[Thinking ${i + 1}] ${truncatedReasoningText}`,
786
+ {
787
+ body: reasoningText,
788
+ contentType: "text/plain"
789
+ }
790
+ );
791
+ }
773
792
  return responseJson;
774
793
  });
775
794
  let combinedMessages = [];
@@ -778,6 +797,7 @@ var Agent = class {
778
797
  for (const agentResponse of agentResponses) {
779
798
  const {
780
799
  activePage: newActivePage,
800
+ failureReason: maybeFailureReason,
781
801
  finalSuccess: maybeFinal,
782
802
  result
783
803
  } = await execResponse({
@@ -789,6 +809,7 @@ var Agent = class {
789
809
  activePage = newActivePage;
790
810
  combinedMessages.push(result.message);
791
811
  finalSuccess = maybeFinal ?? finalSuccess;
812
+ failureReason = maybeFailureReason ?? failureReason;
792
813
  if (result.isError) {
793
814
  aggregatedIsError = true;
794
815
  }
@@ -806,7 +827,10 @@ var Agent = class {
806
827
  } finally {
807
828
  this.browserContext.off("page", onNewPage);
808
829
  }
809
- return { success: finalSuccess ?? false };
830
+ const success = finalSuccess ?? false;
831
+ if (!success) {
832
+ throw new Error(failureReason ?? "Agent failed to complete the task");
833
+ }
810
834
  });
811
835
  }
812
836
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Page as InternalPage } from \"@playwright/test\";\n\nimport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\n\nimport { stablyPlaywrightMatchers } from \"./expect\";\nimport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n} from \"./playwright-augment/augment\";\nimport { requireApiKey } from \"./runtime\";\n\nexport { setApiKey } from \"./runtime\";\nexport { Agent } from \"./playwright-augment/methods/agent\";\n\nexport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\nexport type ScreenshotPromptOptions =\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n import(\"@playwright/test\").PageAssertionsToHaveScreenshotOptions;\nexport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n stablyPlaywrightMatchers,\n requireApiKey,\n};\n\n// eslint-disable-next-line unused-imports/no-unused-vars\nexport type Expect<T = InternalPage> = {\n toMatchScreenshotPrompt(\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<void>;\n};\n\ndeclare module \"@playwright/test\" {\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Locator {\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Page {\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface BrowserContext {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within this browser context and can interact with all pages in the context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const context = await browser.newContext();\n * const page = await context.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent for this context\n * const agent = context.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Click the login button and enter credentials', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Browser {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within a browser context and can interact with all pages in that context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const browser = await chromium.launch();\n * const page = await browser.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent\n * const agent = browser.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Fill out the registration form and submit', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n}\n","import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v1/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves with the result of the agent's actions\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * const result = await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * if (result.success) {\n * console.log('Agent completed the task successfully');\n * }\n * ```\n */\n async act(\n prompt: string,\n options: AgentActOptions,\n ): Promise<{ success: boolean }> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`,\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content)\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n },\n );\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":"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","names":["png","import_test","STABLY_API_URL","alias","import_test","STABLY_API_URL"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Page as InternalPage } from \"@playwright/test\";\n\nimport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\n\nimport { stablyPlaywrightMatchers } from \"./expect\";\nimport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n} from \"./playwright-augment/augment\";\nimport { requireApiKey } from \"./runtime\";\n\nexport { setApiKey } from \"./runtime\";\nexport { Agent } from \"./playwright-augment/methods/agent\";\n\nexport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\nexport type ScreenshotPromptOptions =\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n import(\"@playwright/test\").PageAssertionsToHaveScreenshotOptions;\nexport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n stablyPlaywrightMatchers,\n requireApiKey,\n};\n\n// eslint-disable-next-line unused-imports/no-unused-vars\nexport type Expect<T = InternalPage> = {\n toMatchScreenshotPrompt(\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<void>;\n};\n\ndeclare module \"@playwright/test\" {\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Locator {\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Page {\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface BrowserContext {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within this browser context and can interact with all pages in the context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const context = await browser.newContext();\n * const page = await context.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent for this context\n * const agent = context.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Click the login button and enter credentials', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Browser {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within a browser context and can interact with all pages in that context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const browser = await chromium.launch();\n * const page = await browser.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent\n * const agent = browser.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Fill out the registration form and submit', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n}\n","import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({\n pageMetadata: isPage(target)\n ? { title: await target.title(), url: target.url() }\n : undefined,\n prompt: condition,\n screenshot,\n });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v2/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n pageMetadata,\n prompt,\n screenshot,\n}: {\n pageMetadata?: { title: string; url: string };\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n\n const metadata = {\n prompt,\n ...(pageMetadata?.title ? { pageTitle: pageMetadata.title } : {}),\n ...(pageMetadata?.url ? { pageUrl: pageMetadata.url } : {}),\n };\n form.append(\"metadata\", JSON.stringify(metadata));\n\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"screenshot\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves when the agent successfully completes the task\n * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * // Handling failures with try-catch\n * try {\n * await agent.act('Complete the task', { page });\n * console.log('Agent completed the task successfully');\n * } catch (error) {\n * console.error('Agent failed:', error.message);\n * }\n * ```\n */\n async act(prompt: string, options: AgentActOptions): Promise<void> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let failureReason: string | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`,\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content?.trim())\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n // Only attach if there's actual reasoning content\n if (reasoningText) {\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n },\n );\n }\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n failureReason: maybeFailureReason,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n failureReason = maybeFailureReason ?? failureReason;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n const success = finalSuccess ?? false;\n if (!success) {\n throw new Error(failureReason ?? \"Agent failed to complete the task\");\n }\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n failureReason?: string;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n failureReason: success ? undefined : reason,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":"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","names":["png","import_test","STABLY_API_URL","alias","import_test","STABLY_API_URL"]}
package/dist/index.d.mts CHANGED
@@ -52,7 +52,8 @@ declare class Agent {
52
52
  *
53
53
  * @param prompt - Natural language instruction describing what the agent should do
54
54
  * @param options - Configuration for the agent's behavior including the page to operate on
55
- * @returns Promise that resolves with the result of the agent's actions
55
+ * @returns Promise that resolves when the agent successfully completes the task
56
+ * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
56
57
  *
57
58
  * @example
58
59
  * ```typescript
@@ -63,20 +64,22 @@ declare class Agent {
63
64
  * await agent.act('Navigate to settings, enable notifications, and save changes', { page });
64
65
  *
65
66
  * // With custom options
66
- * const result = await agent.act('Complete the checkout process', {
67
+ * await agent.act('Complete the checkout process', {
67
68
  * page,
68
69
  * maxCycles: 20,
69
70
  * model: 'gpt-4'
70
71
  * });
71
72
  *
72
- * if (result.success) {
73
+ * // Handling failures with try-catch
74
+ * try {
75
+ * await agent.act('Complete the task', { page });
73
76
  * console.log('Agent completed the task successfully');
77
+ * } catch (error) {
78
+ * console.error('Agent failed:', error.message);
74
79
  * }
75
80
  * ```
76
81
  */
77
- act(prompt: string, options: AgentActOptions): Promise<{
78
- success: boolean;
79
- }>;
82
+ act(prompt: string, options: AgentActOptions): Promise<void>;
80
83
  }
81
84
 
82
85
  type ExtractSchema = {
package/dist/index.d.ts CHANGED
@@ -52,7 +52,8 @@ declare class Agent {
52
52
  *
53
53
  * @param prompt - Natural language instruction describing what the agent should do
54
54
  * @param options - Configuration for the agent's behavior including the page to operate on
55
- * @returns Promise that resolves with the result of the agent's actions
55
+ * @returns Promise that resolves when the agent successfully completes the task
56
+ * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
56
57
  *
57
58
  * @example
58
59
  * ```typescript
@@ -63,20 +64,22 @@ declare class Agent {
63
64
  * await agent.act('Navigate to settings, enable notifications, and save changes', { page });
64
65
  *
65
66
  * // With custom options
66
- * const result = await agent.act('Complete the checkout process', {
67
+ * await agent.act('Complete the checkout process', {
67
68
  * page,
68
69
  * maxCycles: 20,
69
70
  * model: 'gpt-4'
70
71
  * });
71
72
  *
72
- * if (result.success) {
73
+ * // Handling failures with try-catch
74
+ * try {
75
+ * await agent.act('Complete the task', { page });
73
76
  * console.log('Agent completed the task successfully');
77
+ * } catch (error) {
78
+ * console.error('Agent failed:', error.message);
74
79
  * }
75
80
  * ```
76
81
  */
77
- act(prompt: string, options: AgentActOptions): Promise<{
78
- success: boolean;
79
- }>;
82
+ act(prompt: string, options: AgentActOptions): Promise<void>;
80
83
  }
81
84
 
82
85
  type ExtractSchema = {
package/dist/index.mjs CHANGED
@@ -34,11 +34,11 @@ var isObject = (value) => {
34
34
  // src/ai/metadata.ts
35
35
  var SDK_METADATA_HEADERS = {
36
36
  "X-Client-Name": "stably-playwright-sdk-js",
37
- "X-Client-Version": "2.0.0-next.1"
37
+ "X-Client-Version": "2.0.0"
38
38
  };
39
39
 
40
40
  // src/ai/verify-prompt.ts
41
- var PROMPT_ASSERTION_PATH = "internal/v1/assert";
41
+ var PROMPT_ASSERTION_PATH = "internal/v2/assert";
42
42
  var STABLY_API_URL = process.env.STABLY_API_URL || "https://api.stably.ai";
43
43
  var PROMPT_ASSERTION_ENDPOINT = new URL(
44
44
  PROMPT_ASSERTION_PATH,
@@ -68,15 +68,21 @@ var parseErrorResponse = (value) => {
68
68
  return typeof error !== "string" ? void 0 : { error };
69
69
  };
70
70
  async function verifyPrompt({
71
+ pageMetadata,
71
72
  prompt,
72
73
  screenshot
73
74
  }) {
74
75
  const apiKey = requireApiKey();
75
76
  const form = new FormData();
76
- form.append("prompt", prompt);
77
+ const metadata = {
78
+ prompt,
79
+ ...pageMetadata?.title ? { pageTitle: pageMetadata.title } : {},
80
+ ...pageMetadata?.url ? { pageUrl: pageMetadata.url } : {}
81
+ };
82
+ form.append("metadata", JSON.stringify(metadata));
77
83
  const u8 = Uint8Array.from(screenshot);
78
84
  const blob = new Blob([u8], { type: "image/png" });
79
- form.append("image", blob, "screenshot.png");
85
+ form.append("screenshot", blob, "screenshot.png");
80
86
  const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {
81
87
  body: form,
82
88
  headers: {
@@ -385,7 +391,11 @@ var stablyPlaywrightMatchers = {
385
391
  }
386
392
  const targetType = isPage(target) ? "page" : "locator";
387
393
  const screenshot = await takeStableScreenshot(target, options);
388
- const verifyResult = await verifyPrompt({ prompt: condition, screenshot });
394
+ const verifyResult = await verifyPrompt({
395
+ pageMetadata: isPage(target) ? { title: await target.title(), url: target.url() } : void 0,
396
+ prompt: condition,
397
+ screenshot
398
+ });
389
399
  const testInfo = test.info();
390
400
  testInfo.attachments.push({
391
401
  body: Buffer.from(
@@ -613,6 +623,7 @@ ${ariaSnapshot}` }
613
623
  const { reason, success } = agentResponse;
614
624
  return {
615
625
  activePage,
626
+ failureReason: success ? void 0 : reason,
616
627
  finalSuccess: success,
617
628
  result: { message: reason, shouldTerminate: true }
618
629
  };
@@ -641,7 +652,8 @@ var Agent = class {
641
652
  *
642
653
  * @param prompt - Natural language instruction describing what the agent should do
643
654
  * @param options - Configuration for the agent's behavior including the page to operate on
644
- * @returns Promise that resolves with the result of the agent's actions
655
+ * @returns Promise that resolves when the agent successfully completes the task
656
+ * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
645
657
  *
646
658
  * @example
647
659
  * ```typescript
@@ -652,14 +664,18 @@ var Agent = class {
652
664
  * await agent.act('Navigate to settings, enable notifications, and save changes', { page });
653
665
  *
654
666
  * // With custom options
655
- * const result = await agent.act('Complete the checkout process', {
667
+ * await agent.act('Complete the checkout process', {
656
668
  * page,
657
669
  * maxCycles: 20,
658
670
  * model: 'gpt-4'
659
671
  * });
660
672
  *
661
- * if (result.success) {
673
+ * // Handling failures with try-catch
674
+ * try {
675
+ * await agent.act('Complete the task', { page });
662
676
  * console.log('Agent completed the task successfully');
677
+ * } catch (error) {
678
+ * console.error('Agent failed:', error.message);
663
679
  * }
664
680
  * ```
665
681
  */
@@ -677,6 +693,7 @@ var Agent = class {
677
693
  shouldTerminate: false
678
694
  };
679
695
  let finalSuccess;
696
+ let failureReason;
680
697
  let newPageOpenedMsg;
681
698
  const sessionId = crypto.randomUUID();
682
699
  const onNewPage = async (page) => {
@@ -723,16 +740,18 @@ var Agent = class {
723
740
  `Agent call failed: ${JSON.stringify(responseJson)}`
724
741
  );
725
742
  }
726
- const reasoningTexts = responseJson.map((r) => r.content).filter((content) => content !== void 0);
743
+ const reasoningTexts = responseJson.map((r) => r.content?.trim()).filter((content) => content !== void 0);
727
744
  const reasoningText = reasoningTexts.join("\n\n");
728
- const truncatedReasoningText = truncate(reasoningText, 120);
729
- await stepInfo.attach(
730
- `[Thinking ${i + 1}] ${truncatedReasoningText}`,
731
- {
732
- body: reasoningText,
733
- contentType: "text/plain"
734
- }
735
- );
745
+ if (reasoningText) {
746
+ const truncatedReasoningText = truncate(reasoningText, 120);
747
+ await stepInfo.attach(
748
+ `[Thinking ${i + 1}] ${truncatedReasoningText}`,
749
+ {
750
+ body: reasoningText,
751
+ contentType: "text/plain"
752
+ }
753
+ );
754
+ }
736
755
  return responseJson;
737
756
  });
738
757
  let combinedMessages = [];
@@ -741,6 +760,7 @@ var Agent = class {
741
760
  for (const agentResponse of agentResponses) {
742
761
  const {
743
762
  activePage: newActivePage,
763
+ failureReason: maybeFailureReason,
744
764
  finalSuccess: maybeFinal,
745
765
  result
746
766
  } = await execResponse({
@@ -752,6 +772,7 @@ var Agent = class {
752
772
  activePage = newActivePage;
753
773
  combinedMessages.push(result.message);
754
774
  finalSuccess = maybeFinal ?? finalSuccess;
775
+ failureReason = maybeFailureReason ?? failureReason;
755
776
  if (result.isError) {
756
777
  aggregatedIsError = true;
757
778
  }
@@ -769,7 +790,10 @@ var Agent = class {
769
790
  } finally {
770
791
  this.browserContext.off("page", onNewPage);
771
792
  }
772
- return { success: finalSuccess ?? false };
793
+ const success = finalSuccess ?? false;
794
+ if (!success) {
795
+ throw new Error(failureReason ?? "Agent failed to complete the task");
796
+ }
773
797
  });
774
798
  }
775
799
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v1/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves with the result of the agent's actions\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * const result = await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * if (result.success) {\n * console.log('Agent completed the task successfully');\n * }\n * ```\n */\n async act(\n prompt: string,\n options: AgentActOptions,\n ): Promise<{ success: boolean }> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`,\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content)\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n },\n );\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":";;;;;;;;AACA,SAAS,YAAY;;;ACDrB,IAAI,mBAAuC,QAAQ,IAAI;AAEhD,SAAS,UAAU,QAAsB;AAC9C,qBAAmB;AACrB;AAEO,SAAS,YAAgC;AAC9C,SAAO;AACT;AAEO,SAAS,gBAAwB;AACtC,QAAM,SAAS,UAAU;AACzB,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;AClBO,IAAM,WAAW,CAAC,UAAqD;AAC5E,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;;ACAO,IAAM,uBAAuB;AAAA,EAClC,iBAAiB;AAAA,EACjB,oBAAoB;AACtB;;;ACDA,IAAM,wBAAwB;AAC9B,IAAM,iBAAiB,QAAQ,IAAI,kBAAkB;AACrD,IAAM,4BAA4B,IAAI;AAAA,EACpC;AAAA,EACA;AACF,EAAE,SAAS;AAIX,IAAM,uBAAuB,CAAC,UAA0C;AACtE,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,QAAM,EAAE,QAAQ,QAAQ,IAAI;AAC5B,MAAI,OAAO,YAAY,WAAW;AAChC,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,MAAI,WAAW,UAAa,OAAO,WAAW,UAAU;AACtD,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAIA,IAAM,qBAAqB,CACzB,UACoC;AACpC,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,MAAM,IAAI;AAClB,SAAO,OAAO,UAAU,WAAW,SAAY,EAAE,MAAM;AACzD;AAEA,eAAsB,aAAa;AAAA,EACjC;AAAA,EACA;AACF,GAMG;AACD,QAAM,SAAS,cAAc;AAE7B,QAAM,OAAO,IAAI,SAAS;AAC1B,OAAK,OAAO,UAAU,MAAM;AAC5B,QAAM,KAAK,WAAW,KAAK,UAAU;AACrC,QAAM,OAAO,IAAI,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACjD,OAAK,OAAO,SAAS,MAAM,gBAAgB;AAE3C,QAAM,WAAW,MAAM,MAAM,2BAA2B;AAAA,IACtD,MAAM;AAAA,IACN,SAAS;AAAA,MACP,GAAG;AAAA,MACH,eAAe,UAAU,MAAM;AAAA,IACjC;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,SAAS,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,MAAoB;AAErE,MAAI,SAAS,IAAI;AACf,UAAM,EAAE,QAAQ,QAAQ,IAAI,qBAAqB,MAAM;AACvD,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,mBAAmB,MAAM;AACrC,QAAM,IAAI;AAAA,IACR,yBAAyB,SAAS,MAAM,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,EAAE;AAAA,EACzE;AACF;;;ACrFO,SAAS,OAAO,WAAuC;AAC5D,SACE,OAAO,cAAc,YACrB,cAAc,QACd,OAAQ,UAAmB,eAAe,cAC1C,OAAQ,UAAmB,SAAS;AAExC;AAEO,SAAS,UAAU,WAA0C;AAClE,SACE,OAAO,cAAc,YACrB,cAAc,QACd,OAAQ,UAAsB,eAAe,cAC7C,OAAQ,UAAsB,QAAQ;AAE1C;;;ACjBA,YAAY,UAAU;;;ACmBP,SAAR,WAA4B,MAAM,MAAM,QAAQ,OAAO,QAAQ,UAAU,CAAC,GAAG;AAChF,QAAM;AAAA,IACF,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,UAAU,CAAC,KAAK,KAAK,CAAC;AAAA,IACtB,YAAY,CAAC,KAAK,GAAG,CAAC;AAAA,IACtB;AAAA,IAAW;AAAA,IAAc;AAAA,EAC7B,IAAI;AAEJ,MAAI,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,IAAI,KAAM,UAAU,CAAC,YAAY,MAAM;AAC1E,UAAM,IAAI,MAAM,+DAA+D;AAEnF,MAAI,KAAK,WAAW,KAAK,UAAW,UAAU,OAAO,WAAW,KAAK;AACjE,UAAM,IAAI,MAAM,2BAA2B;AAE/C,MAAI,KAAK,WAAW,QAAQ,SAAS,EAAG,OAAM,IAAI,MAAM,8CAA8C;AAGtG,QAAM,MAAM,QAAQ;AACpB,QAAM,MAAM,IAAI,YAAY,KAAK,QAAQ,KAAK,YAAY,GAAG;AAC7D,QAAM,MAAM,IAAI,YAAY,KAAK,QAAQ,KAAK,YAAY,GAAG;AAC7D,MAAI,YAAY;AAEhB,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC1B,QAAI,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG;AAAE,kBAAY;AAAO;AAAA,IAAO;AAAA,EACvD;AACA,MAAI,WAAW;AACX,QAAI,UAAU,CAAC,UAAU;AACrB,eAAS,IAAI,GAAG,IAAI,KAAK,IAAK,eAAc,MAAM,IAAI,GAAG,OAAO,MAAM;AAAA,IAC1E;AACA,WAAO;AAAA,EACX;AAIA,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,CAAC,KAAK,KAAK,GAAG,IAAI;AACxB,QAAM,CAAC,OAAO,OAAO,KAAK,IAAI;AAC9B,QAAM,CAAC,MAAM,MAAM,IAAI,IAAI,gBAAgB;AAC3C,MAAI,OAAO;AAGX,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC7B,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAE5B,YAAM,IAAI,IAAI,QAAQ;AACtB,YAAM,MAAM,IAAI;AAGhB,YAAM,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,WAAW,MAAM,MAAM,KAAK,KAAK,KAAK;AAG5E,UAAI,KAAK,IAAI,KAAK,IAAI,UAAU;AAE5B,cAAM,OAAO,YAAY,MAAM,GAAG,GAAG,OAAO,QAAQ,KAAK,GAAG,KAAK,YAAY,MAAM,GAAG,GAAG,OAAO,QAAQ,KAAK,GAAG;AAChH,YAAI,CAAC,aAAa,MAAM;AAGpB,cAAI,UAAU,CAAC,SAAU,WAAU,QAAQ,KAAK,KAAK,KAAK,GAAG;AAAA,QAEjE,OAAO;AAEH,cAAI,QAAQ;AACR,gBAAI,QAAQ,GAAG;AACX,wBAAU,QAAQ,KAAK,MAAM,MAAM,IAAI;AAAA,YAC3C,OAAO;AACH,wBAAU,QAAQ,KAAK,OAAO,OAAO,KAAK;AAAA,YAC9C;AAAA,UACJ;AACA;AAAA,QACJ;AAAA,MAEJ,WAAW,UAAU,CAAC,UAAU;AAE5B,sBAAc,MAAM,KAAK,OAAO,MAAM;AAAA,MAC1C;AAAA,IACJ;AAAA,EACJ;AAGA,SAAO;AACX;AAGA,SAAS,YAAY,KAAK;AAEtB,SAAO,YAAY,OAAO,GAAG,KAAK,IAAI,sBAAsB;AAChE;AAaA,SAAS,YAAY,KAAK,IAAI,IAAI,OAAO,QAAQ,KAAK,KAAK;AACvD,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,CAAC;AAC7B,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,CAAC;AAC7B,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC;AACrC,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,SAAS,CAAC;AACtC,QAAM,MAAM,KAAK,QAAQ;AACzB,MAAI,SAAS,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,KAAK,IAAI;AACpE,MAAI,MAAM;AACV,MAAI,MAAM;AACV,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,OAAO;AAGX,WAAS,IAAI,IAAI,KAAK,IAAI,KAAK;AAC3B,aAAS,IAAI,IAAI,KAAK,IAAI,KAAK;AAC3B,UAAI,MAAM,MAAM,MAAM,GAAI;AAG1B,YAAM,QAAQ,WAAW,KAAK,KAAK,MAAM,IAAI,IAAI,QAAQ,KAAK,GAAG,IAAI;AAGrE,UAAI,UAAU,GAAG;AACb;AAEA,YAAI,SAAS,EAAG,QAAO;AAAA,MAG3B,WAAW,QAAQ,KAAK;AACpB,cAAM;AACN,eAAO;AACP,eAAO;AAAA,MAGX,WAAW,QAAQ,KAAK;AACpB,cAAM;AACN,eAAO;AACP,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;AAGA,MAAI,QAAQ,KAAK,QAAQ,EAAG,QAAO;AAInC,SAAQ,gBAAgB,KAAK,MAAM,MAAM,OAAO,MAAM,KAAK,gBAAgB,KAAK,MAAM,MAAM,OAAO,MAAM,KACjG,gBAAgB,KAAK,MAAM,MAAM,OAAO,MAAM,KAAK,gBAAgB,KAAK,MAAM,MAAM,OAAO,MAAM;AAC7G;AAUA,SAAS,gBAAgB,KAAK,IAAI,IAAI,OAAO,QAAQ;AACjD,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,CAAC;AAC7B,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,CAAC;AAC7B,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC;AACrC,QAAM,KAAK,KAAK,IAAI,KAAK,GAAG,SAAS,CAAC;AACtC,QAAM,MAAM,IAAI,KAAK,QAAQ,EAAE;AAC/B,MAAI,SAAS,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,KAAK,IAAI;AAGpE,WAAS,IAAI,IAAI,KAAK,IAAI,KAAK;AAC3B,aAAS,IAAI,IAAI,KAAK,IAAI,KAAK;AAC3B,UAAI,MAAM,MAAM,MAAM,GAAI;AAC1B,gBAAU,EAAE,QAAQ,IAAI,IAAI,QAAQ,CAAC;AACrC,UAAI,SAAS,EAAG,QAAO;AAAA,IAC3B;AAAA,EACJ;AACA,SAAO;AACX;AAWA,SAAS,WAAW,MAAM,MAAM,GAAG,GAAG,OAAO;AACzC,QAAM,KAAK,KAAK,CAAC;AACjB,QAAM,KAAK,KAAK,IAAI,CAAC;AACrB,QAAM,KAAK,KAAK,IAAI,CAAC;AACrB,QAAM,KAAK,KAAK,IAAI,CAAC;AACrB,QAAM,KAAK,KAAK,CAAC;AACjB,QAAM,KAAK,KAAK,IAAI,CAAC;AACrB,QAAM,KAAK,KAAK,IAAI,CAAC;AACrB,QAAM,KAAK,KAAK,IAAI,CAAC;AAErB,MAAI,KAAK,KAAK;AACd,MAAI,KAAK,KAAK;AACd,MAAI,KAAK,KAAK;AACd,QAAM,KAAK,KAAK;AAEhB,MAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAI,QAAO;AAErC,MAAI,KAAK,OAAO,KAAK,KAAK;AACtB,UAAM,KAAK,KAAK,OAAO,IAAI;AAC3B,UAAM,KAAK,KAAK,QAAQ,IAAI,oBAAoB,KAAK;AACrD,UAAM,KAAK,KAAK,QAAQ,IAAI,oBAAoB,KAAK;AACrD,UAAM,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM;AACrC,UAAM,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM;AACrC,UAAM,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM;AAAA,EACzC;AAEA,QAAM,IAAI,KAAK,aAAa,KAAK,aAAa,KAAK;AAEnD,MAAI,MAAO,QAAO;AAElB,QAAM,IAAI,KAAK,aAAa,KAAK,YAAa,KAAK;AACnD,QAAM,IAAI,KAAK,aAAa,KAAK,aAAa,KAAK;AAEnD,QAAM,QAAQ,SAAS,IAAI,IAAI,QAAQ,IAAI,IAAI,SAAS,IAAI;AAG5D,SAAO,IAAI,IAAI,CAAC,QAAQ;AAC5B;AASA,SAAS,UAAU,QAAQ,KAAK,GAAG,GAAG,GAAG;AACrC,SAAO,MAAM,CAAC,IAAI;AAClB,SAAO,MAAM,CAAC,IAAI;AAClB,SAAO,MAAM,CAAC,IAAI;AAClB,SAAO,MAAM,CAAC,IAAI;AACtB;AAQA,SAAS,cAAc,KAAK,GAAG,OAAO,QAAQ;AAC1C,QAAM,MAAM,OAAO,IAAI,CAAC,IAAI,aAAa,IAAI,IAAI,CAAC,IAAI,aAAa,IAAI,IAAI,CAAC,IAAI,aAAa,OAAO,QAAQ,IAAI,IAAI,CAAC,IAAI;AACzH,YAAU,QAAQ,GAAG,KAAK,KAAK,GAAG;AACtC;;;AD3QA,SAAS,WAAW;AAEpB,IAAM,QAAQ,CAAC,WAA4B;AACzC,SACE,OAAO,UAAU,KACjB,OAAO,CAAC,MAAM,OACd,OAAO,CAAC,MAAM,MACd,OAAO,CAAC,MAAM,MACd,OAAO,CAAC,MAAM,MACd,OAAO,CAAC,MAAM,MACd,OAAO,CAAC,MAAM,MACd,OAAO,CAAC,MAAM,MACd,OAAO,CAAC,MAAM;AAElB;AAEA,IAAM,SAAS,CAAC,WAA4B;AAC1C,SAAO,OAAO,UAAU,KAAK,OAAO,CAAC,MAAM,OAAQ,OAAO,CAAC,MAAM;AACnE;AAEA,IAAM,cAAc,CAClB,WACwD;AACxD,MAAI,MAAM,MAAM,GAAG;AACjB,UAAMA,OAAM,IAAI,KAAK,KAAK,MAAM;AAChC,WAAO,EAAE,MAAMA,KAAI,MAAM,QAAQA,KAAI,QAAQ,OAAOA,KAAI,MAAM;AAAA,EAChE;AACA,MAAI,OAAO,MAAM,GAAG;AAClB,UAAM,MAAW,YAAO,QAAQ,EAAE,oBAAoB,KAAK,CAAC;AAC5D,WAAO,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI,QAAQ,OAAO,IAAI,MAAM;AAAA,EAChE;AAEA,QAAM,MAAM,IAAI,KAAK,KAAK,MAAM;AAChC,SAAO,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI,QAAQ,OAAO,IAAI,MAAM;AAChE;AAEO,IAAM,mBAAmB,CAAC;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF,MAIe;AACb,QAAM,gBAAgB,YAAY,MAAM;AACxC,QAAM,gBAAgB,YAAY,MAAM;AACxC,MACE,cAAc,UAAU,cAAc,SACtC,cAAc,WAAW,cAAc,QACvC;AACA,WAAO;AAAA,EACT;AACA,QAAM,eAAe,IAAI;AAAA,IACvB,cAAc,QAAQ,cAAc,SAAS;AAAA,EAC/C;AACA,QAAM,gBAAgB;AAAA,IACpB,cAAc;AAAA,IACd,cAAc;AAAA,IACd;AAAA,IACA,cAAc;AAAA,IACd,cAAc;AAAA,IACd,EAAE,UAAU;AAAA,EACd;AAEA,SAAO,kBAAkB;AAC3B;;;AE9DA,eAAsB,qBACpB,QACA,SACiB;AACjB,QAAM,OAAO,OAAO,MAAM,IAAI,SAAS,OAAO,KAAK;AAInD,QAAM,eACH,SAA8C,WAAW;AAE5D,QAAM,wBAAwB,KAAK,MAAM,eAAe,IAAI;AAC5D,QAAM,oBAAoB,KAAK;AAAA,IAC7B;AAAA,IACA,KAAK,IAAI,KAAK,qBAAqB;AAAA,EACrC;AACA,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,MAAI;AACJ,MAAI;AACJ,QAAM,gBAAgB,CAAC,GAAG,KAAK,KAAK,GAAG;AACvC,MAAI,mBAAmB;AAIvB,QAAM,iBAAiB,YAA6B;AAClD,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI;AACF,eAAO,MAAM,OAAO,WAAW,OAAO;AAAA,MACxC,QAAQ;AACN,cAAM,KAAK,eAAe,GAAG;AAC7B;AAAA,MACF;AAAA,IACF;AACA,WAAO,MAAM,OAAO,WAAW,OAAO;AAAA,EACxC;AAEA,SAAO,MAAM;AACX,QAAI,KAAK,IAAI,KAAK,UAAU;AAC1B;AAAA,IACF;AACA,UAAM,QAAQ,cAAc,SAAS,cAAc,MAAM,IAAK;AAC9D,QAAI,OAAO;AACT,YAAM,KAAK,eAAe,KAAK;AAAA,IACjC;AACA,eAAW;AACX,aAAS,MAAM,eAAe;AAC9B,QACE,CAAC,oBACD,UACA,YACA,iBAAiB;AAAA,MACf,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW,SAAS,aAAa;AAAA,IACnC,CAAC,GACD;AACA,aAAO;AAAA,IACT;AACA,uBAAmB;AAAA,EACrB;AACA,SAAO,UAAW,MAAM,eAAe;AACzC;;;ARrDA,SAAS,qBAAqB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMW;AACT,QAAM,cAAc,QAAQ,mBAAmB;AAC/C,QAAM,SAAS,UAAU,WAAW;AAEpC,MAAI,UAAU,YAAY,UAAU,IAAI,WAAW,IAAI,KAAK,UAAU,SAAS,CAAC,SAAS,MAAM;AAC/F,MAAI,QAAQ;AACV,eAAW;AAAA;AAAA,UAAe,MAAM;AAAA,EAClC;AAEA,SAAO;AACT;AAEO,IAAM,2BAA2B;AAAA,EACtC,MAAM,wBAEJ,UACA,WACA,SAC4B;AAC5B,UAAM,SAAS,OAAO,QAAQ,IAC1B,WACA,UAAU,QAAQ,IAChB,WACA;AACN,QAAI,CAAC,QAAQ;AAEX,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,aAA+B,OAAO,MAAM,IAAI,SAAS;AAG/D,UAAM,aAAa,MAAM,qBAAqB,QAAQ,OAAO;AAE7D,UAAM,eAAe,MAAM,aAAa,EAAE,QAAQ,WAAW,WAAW,CAAC;AAEzE,UAAM,WAAW,KAAK,KAAK;AAC3B,aAAS,YAAY,KAAK;AAAA,MACxB,MAAM,OAAO;AAAA,QACX,KAAK;AAAA,UACH;AAAA,YACE,MAAM,aAAa;AAAA,YACnB,QAAQ;AAAA,YACR,WAAW,aAAa;AAAA,UAC1B;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,MACA,aAAa;AAAA,MACb,MAAM;AAAA,IACR,CAAC;AAED,WAAO;AAAA,MACL,SAAS,MACP,qBAAqB;AAAA,QACnB;AAAA,QACA,SAAS,aAAa;AAAA,QACtB,OAAO,KAAK;AAAA,QACZ,QAAQ,aAAa;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,MACH,MAAM;AAAA,MACN,MAAM,aAAa;AAAA,IACrB;AAAA,EACF;AACF;;;AS9FA,SAAS,QAAAC,aAAY;;;ACFd,IAAM,WAAW,CAAC,KAAa,WACpC,IAAI,UAAU,UAAU,IAAI,UAAU,IAClC,MACA,GAAG,IAAI,MAAM,GAAG,SAAS,CAAC,CAAC;;;ACA1B,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASa;AACX,QAAM,OAAO,IAAI,SAAS;AAC1B,QAAM,eAAe,WAAW,aAAa;AAE7C,QAAM,OAAO,MAAM,KAAK,WAAW,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO;AAAA,IACpE;AAAA,IACA,KAAK,KAAK,IAAI;AAAA,EAChB,EAAE;AAEF,QAAM,kBAAkB,WAAW,IAAI,UAAU;AAEjD,QAAM,WAAoC;AAAA,IACxC,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AAEA,MAAI,OAAO;AACT,aAAS,QAAQ;AAAA,EACnB;AACA,MAAI,SAAS;AACX,aAAS,UAAU;AAAA,EACrB;AACA,MAAI,mBAAmB;AACrB,aAAS,oBAAoB;AAAA,EAC/B;AACA,MAAI,cAAc;AAChB,aAAS,iBAAiB;AAAA,EAC5B;AACA,MAAI,iBAAiB;AACnB,aAAS,kBAAkB;AAAA,EAC7B;AAEA,QAAM,eAAe,IAAI,KAAK,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAG;AAAA,IACxD,MAAM;AAAA,EACR,CAAC;AACD,OAAK,OAAO,YAAY,cAAc,eAAe;AAErD,QAAM,kBAAkB,WAAW,KAAK,UAAU;AAClD,QAAM,iBAAiB,IAAI,KAAK,CAAC,eAAe,GAAG,EAAE,MAAM,YAAY,CAAC;AACxE,OAAK,OAAO,cAAc,gBAAgB,gBAAgB;AAE1D,SAAO;AACT;;;ACjDA,IAAM,wBAAwB;AAE9B,eAAsB,aAAa;AAAA,EACjC,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,MAAI,aAAa;AACjB,MAAI;AACF,YAAQ,cAAc,QAAQ;AAAA,MAC5B,KAAK,OAAO;AACV,cAAM,EAAE,KAAK,IAAI;AACjB,YAAI,MAAM;AACR,gBAAM,WAAW,SAAS,MAAM,IAAI;AACpC,iBAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,YAAY,IAAI,IAAI,EAAE;AAAA,QAChE;AACA,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,cAAc,EAAE;AAAA,MAC1D;AAAA,MACA,KAAK,QAAQ;AACX,cAAM,EAAE,KAAK,IAAI;AACjB,cAAM,WAAW,SAAS,KAAK,IAAI;AACnC,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,UAAU,IAAI,IAAI,EAAE;AAAA,MAC9D;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,CAAC,GAAG,CAAC,IAAI,cAAc;AAC7B,cAAM,WAAW,MAAM,KAAK,GAAG,CAAC;AAChC,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,wBAAwB,EAAE;AAAA,MACpE;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,CAAC,GAAG,CAAC,IAAI,cAAc;AAC7B,cAAM,WAAW,MAAM,MAAM,GAAG,CAAC;AACjC,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,uBAAuB,EAAE;AAAA,MACnE;AAAA,MACA,KAAK,eAAe;AAClB,cAAM,CAAC,GAAG,CAAC,IAAI,cAAc;AAC7B,cAAM,WAAW,MAAM,MAAM,GAAG,GAAG,EAAE,QAAQ,QAAQ,CAAC;AACtD,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,wBAAwB,EAAE;AAAA,MACpE;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,CAAC,GAAG,CAAC,IAAI,cAAc;AAC7B,cAAM,WAAW,MAAM,SAAS,GAAG,CAAC;AACpC,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,yBAAyB,EAAE;AAAA,MACrE;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,CAAC,GAAG,CAAC,IAAI,cAAc;AAC7B,cAAM,WAAW,MAAM,MAAM,GAAG,GAAG,EAAE,YAAY,EAAE,CAAC;AACpD,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,yBAAyB,EAAE;AAAA,MACrE;AAAA,MACA,KAAK,mBAAmB;AACtB,cAAM,CAAC,QAAQ,MAAM,IAAI,cAAc;AACvC,cAAM,CAAC,MAAM,IAAI,IAAI,cAAc;AACnC,cAAM,WAAW,MAAM,KAAK,QAAQ,MAAM;AAC1C,cAAM,WAAW,MAAM,KAAK;AAC5B,cAAM,WAAW,MAAM,KAAK,MAAM,IAAI;AACtC,cAAM,WAAW,MAAM,GAAG;AAC1B,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,iBAAiB,EAAE;AAAA,MAC7D;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,qBAAqB,UAAU;AACrC,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,sBAAsB,EAAE;AAAA,MAClE;AAAA,MACA,KAAK,QAAQ;AACX,cAAM,SAAS,cAAc,gBAAgB;AAC7C,cAAM,WAAW,eAAe,MAAM;AACtC,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,UAAU,MAAM,KAAK,EAAE;AAAA,MACjE;AAAA,MACA,KAAK,mBAAmB;AACtB,cAAM,WAAW,KAAK,cAAc,GAAG;AACvC,eAAO;AAAA,UACL;AAAA,UACA,QAAQ,EAAE,SAAS,iBAAiB,cAAc,GAAG,IAAI;AAAA,QAC3D;AAAA,MACF;AAAA,MACA,KAAK,eAAe;AAClB,cAAM,UAAU,MAAM,eAAe,QAAQ;AAC7C,cAAM,QAAQ,KAAK,cAAc,GAAG;AACpC,cAAM,QAAQ,iBAAiB,kBAAkB;AACjD,qBAAa;AACb,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,iBAAiB,EAAE;AAAA,MAC7D;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,QAAQ,MAAM,KAAK,WAAW,QAAQ,CAAC,EAAE;AAAA,UAC7C,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,cAAc;AAAA,QACzC;AACA,cAAM,OAAO,QAAQ,CAAC;AACtB,YAAI,CAAC,MAAM;AACT,gBAAM,IAAI;AAAA,YACR,kBAAkB,cAAc,SAAS;AAAA,UAC3C;AAAA,QACF;AACA,cAAM,KAAK,aAAa;AACxB,qBAAa;AACb,eAAO;AAAA,UACL;AAAA,UACA,QAAQ,EAAE,SAAS,gBAAgB,cAAc,SAAS,IAAI;AAAA,QAChE;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,cAAM,CAAC,GAAG,CAAC,IAAI,cAAc;AAC7B,cAAM,WAAW,MAAM,KAAK,GAAG,CAAC;AAChC,YAAI,SAAS;AACb,YAAI,SAAS;AACb,gBAAQ,cAAc,kBAAkB;AAAA,UACtC,KAAK;AACH,qBAAS,CAAC,cAAc;AACxB;AAAA,UACF,KAAK;AACH,qBAAS,cAAc;AACvB;AAAA,UACF,KAAK;AACH,qBAAS,CAAC,cAAc;AACxB;AAAA,UACF,KAAK;AACH,qBAAS,cAAc;AACvB;AAAA,QACJ;AACA,cAAM,WAAW,MAAM,MAAM,QAAQ,MAAM;AAC3C,eAAO;AAAA,UACL;AAAA,UACA,QAAQ,EAAE,SAAS,YAAY,cAAc,gBAAgB,GAAG;AAAA,QAClE;AAAA,MACF;AAAA,MACA,KAAK,iBAAiB;AACpB,cAAM,MAAM,MAAM,WAAW,OAAO;AACpC,YAAI,CAAC,KAAK;AACR,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC1D;AACA,eAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,iBAAiB,EAAE;AAAA,MAC7D;AAAA,MACA,KAAK,iBAAiB;AACpB,cAAM,eAAe,MACnB,WACA,eAAe;AACjB,eAAO;AAAA,UACL;AAAA,UACA,QAAQ,EAAE,SAAS;AAAA,EAAmB,YAAY,GAAG;AAAA,QACvD;AAAA,MACF;AAAA,MACA,KAAK,kBAAkB;AACrB,cAAM,EAAE,QAAQ,QAAQ,IAAI;AAC5B,eAAO;AAAA,UACL;AAAA,UACA,cAAc;AAAA,UACd,QAAQ,EAAE,SAAS,QAAQ,iBAAiB,KAAK;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,WAAO,EAAE,YAAY,QAAQ,EAAE,SAAS,MAAM,QAAQ,EAAE;AAAA,EAC1D;AACF;;;AH5IA,IAAM,aAAa;AAEnB,IAAMC,kBAAiB,QAAQ,IAAI,kBAAkB;AACrD,IAAM,iBAAiB,IAAI,IAAI,YAAYA,eAAc,EAAE,SAAS;AAgB7D,IAAM,QAAN,MAAY;AAAA,EACjB,YAAqB,gBAAgC;AAAhC;AAAA,EAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiCtD,MAAM,IACJ,QACA,SAC+B;AAC/B,UAAM,SAAS,cAAc;AAE7B,UAAM,YAAY,QAAQ,aAAa;AAEvC,UAAM,aAAa,oBAAI,IAAkB;AACzC,SAAK,eAAe,MAAM,EAAE,QAAQ,CAAC,MAAM,UAAU;AACnD,iBAAW,IAAI,MAAM,OAAO,QAAQ,CAAC,EAAE;AAAA,IACzC,CAAC;AAED,QAAI,aAAa,QAAQ;AACzB,QAAI,eAAkC;AAAA,MACpC,SAAS;AAAA,MACT,SAAS;AAAA,MACT,iBAAiB;AAAA,IACnB;AACA,QAAI;AACJ,QAAI;AAEJ,UAAM,YAAY,OAAO,WAAW;AAEpC,UAAM,YAAY,OAAO,SAAe;AACtC,YAAM,KAAK,iBAAiB,kBAAkB;AAC9C,UAAI,CAAC,WAAW,IAAI,IAAI,GAAG;AACzB,cAAMC,SAAQ,OAAO,WAAW,OAAO,CAAC;AACxC,mBAAW,IAAI,MAAMA,MAAK;AAAA,MAC5B;AACA,YAAM,KAAK,aAAa;AACxB,mBAAa;AAEb,YAAM,QAAQ,WAAW,IAAI,IAAI;AACjC,yBAAmB,kBAAkB,KAAK,KAAK,KAAK,IAAI,CAAC;AAAA,IAC3D;AAEA,SAAK,eAAe,GAAG,QAAQ,SAAS;AAExC,WAAO,MAAMC,MAAK,KAAK,WAAW,MAAM,IAAI,YAAY;AACtD,UAAI;AACF,iBAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,cAAI,aAAa,iBAAiB;AAChC;AAAA,UACF;AAEA,gBAAM,iBACJ,MAAMA,MAAK,KAAK,aAAa,IAAI,CAAC,KAAK,OAAO,aAAa;AACzD,kBAAM,aAAa,MAAM,qBAAqB,UAAU;AAExD,kBAAM,WAAW,MAAM,MAAM,gBAAgB;AAAA,cAC3C,MAAM,sBAAsB;AAAA,gBAC1B;AAAA,gBACA,mBAAmB,mBACf,EAAE,gBAAgB,iBAAiB,IACnC;AAAA,gBACJ,SAAS,aAAa;AAAA,gBACtB,SAAS,aAAa;AAAA,gBACtB,OAAO,QAAQ;AAAA,gBACf;AAAA,gBACA;AAAA,gBACA;AAAA,cACF,CAAC;AAAA,cACD,SAAS;AAAA,gBACP,GAAG;AAAA,gBACH,eAAe,UAAU,MAAM;AAAA,cACjC;AAAA,cACA,QAAQ;AAAA,YACV,CAAC;AAGD,+BAAmB;AACnB,kBAAM,eAAgB,MAAM,SAAS,KAAK;AAE1C,gBAAI,CAAC,SAAS,IAAI;AAChB,oBAAM,IAAI;AAAA,gBACR,sBAAsB,KAAK,UAAU,YAAY,CAAC;AAAA,cACpD;AAAA,YACF;AAGA,kBAAM,iBAAiB,aACpB,IAAI,CAAC,MAAM,EAAE,OAAO,EACpB,OAAO,CAAC,YAAY,YAAY,MAAS;AAE5C,kBAAM,gBAAgB,eAAe,KAAK,MAAM;AAEhD,kBAAM,yBAAyB,SAAS,eAAe,GAAG;AAE1D,kBAAM,SAAS;AAAA,cACb,aAAa,IAAI,CAAC,KAAK,sBAAsB;AAAA,cAC7C;AAAA,gBACE,MAAM;AAAA,gBACN,aAAa;AAAA,cACf;AAAA,YACF;AAEA,mBAAO;AAAA,UACT,CAAC;AAEH,cAAI,mBAA6B,CAAC;AAClC,cAAI,oBAAoB;AACxB,cAAI,4BAA4B;AAEhC,qBAAW,iBAAiB,gBAAgB;AAC1C,kBAAM;AAAA,cACJ,YAAY;AAAA,cACZ,cAAc;AAAA,cACd;AAAA,YACF,IAAI,MAAM,aAAa;AAAA,cACrB;AAAA,cACA;AAAA,cACA,gBAAgB,KAAK;AAAA,cACrB;AAAA,YACF,CAAC;AACD,yBAAa;AACb,6BAAiB,KAAK,OAAO,OAAO;AACpC,2BAAe,cAAc;AAC7B,gBAAI,OAAO,SAAS;AAClB,kCAAoB;AAAA,YACtB;AACA,gBAAI,OAAO,iBAAiB;AAC1B,0CAA4B;AAC5B;AAAA,YACF;AAAA,UACF;AAEA,yBAAe;AAAA,YACb,SAAS;AAAA,YACT,SAAS,iBAAiB,KAAK,IAAI;AAAA,YACnC,iBAAiB;AAAA,UACnB;AAAA,QACF;AAAA,MACF,UAAE;AACA,aAAK,eAAe,IAAI,QAAQ,SAAS;AAAA,MAC3C;AAEA,aAAO,EAAE,SAAS,gBAAgB,MAAM;AAAA,IAC1C,CAAC;AAAA,EACH;AACF;AAEO,IAAM,iBAAiB,CAAC,mBAC7B,IAAI,MAAM,cAAc;;;AItO1B,SAAS,QAAAC,aAAY;AAsBrB,IAAM,eAAe;AACrB,IAAMC,kBAAiB,QAAQ,IAAI,kBAAkB;AACrD,IAAM,mBAAmB,IAAI,IAAI,cAAcA,eAAc,EAAE,SAAS;AAExE,IAAM,SAA4B,MAAM;AACtC,MAAI;AAEF,WAAO,UAAQ,aAAa;AAAA,EAC9B,QAAQ;AACN,WAAO;AAAA,EACT;AACF,GAAG;AAQH,IAAM,uBAAuB,CAAC,UAAgD;AAC5E,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,YAAY,MAAM;AAC1B,WAAO,WAAW;AAAA,EACpB;AAEA,SAAO,MAAM,YAAY,SAAS,OAAO,MAAM,UAAU;AAC3D;AAEA,IAAM,kBAAkB,CAAC,UAA2C;AAClE,SAAO,SAAS,KAAK,KAAK,OAAO,MAAM,UAAU;AACnD;AAEA,IAAM,yBAAN,cAAqC,MAAM;AAAA,EACzC,YACE,SACS,QACT;AACA,UAAM,OAAO;AAFJ;AAGT,SAAK,OAAO;AAAA,EACd;AACF;AAEA,eAAe,mBACb,QACA,OAC0B;AAC1B,QAAM,SAAS,MAAM,OAAO,eAAe,KAAK;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,OAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,SAAO,OAAO;AAChB;AAeA,eAAsB,QAAiC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AACF,GAAwE;AACtE,MAAI,UAAU,CAAC,OAAO;AACpB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aACJ,UAAU,QACN,OAAO;AAAA;AAAA,IAEL;AAAA,EACF,IACA;AAEN,SAAO,MAAMC,MAAK,KAAK,aAAa,MAAM,IAAI,OAAO,aAAa;AAChE,UAAM,SAAS,cAAc;AAE7B,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,UAAU,MAAM;AAC5B,QAAI,YAAY;AACd,WAAK,OAAO,cAAc,KAAK,UAAU,UAAU,CAAC;AAAA,IACtD;AAGA,UAAM,YAAY,MAAO,cAAsB,WAAW,EAAE,MAAM,MAAM,CAAC;AACzE,UAAM,KAAK,WAAW,KAAK,SAAS;AACpC,UAAM,OAAO,IAAI,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACjD,SAAK,OAAO,SAAS,MAAM,gBAAgB;AAE3C,UAAM,WAAW,MAAM,MAAM,kBAAkB;AAAA,MAC7C,MAAM;AAAA,MACN,SAAS;AAAA,QACP,GAAG;AAAA,QACH,eAAe,UAAU,MAAM;AAAA,MACjC;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,MAAM,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,MAAoB;AAElE,QAAI,SAAS,IAAI;AACf,UAAI,CAAC,qBAAqB,GAAG,GAAG;AAC9B,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AAEA,UAAI,CAAC,IAAI,SAAS;AAChB,cAAM,SAAS,OAAO,mBAAmB;AAAA,UACvC,MAAM,IAAI;AAAA,UACV,aAAa;AAAA,QACf,CAAC;AACD,cAAM,IAAI,MAAM,mBAAmB,IAAI,KAAK,EAAE;AAAA,MAChD;AAEA,YAAM,EAAE,MAAM,IAAI;AAClB,YAAM,OACJ,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,OAAO,MAAM,CAAC;AACnE,YAAM,SAAS,OAAO,oBAAoB;AAAA,QACxC;AAAA,QACA,aAAa;AAAA,MACf,CAAC;AAED,aAAO,SACH,MAAM,mBAAmB,QAAQ,KAAK,IACtC,OAAO,UAAU,WACf,QACA,KAAK,UAAU,KAAK;AAAA,IAC5B;AAEA,UAAM,IAAI,MAAM,gBAAgB,GAAG,IAAI,IAAI,QAAQ,gBAAgB;AAAA,EACrE,CAAC;AACH;;;ACnJA,SAAS,cAAc,eAA8C;AACnE,QAAM,OAAQ,OACZ,QACA,YACG;AACH,QAAI,SAAS,QAAQ;AACnB,aAAO,QAAQ;AAAA,QACb;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,WAAO,QAAQ,EAAE,eAAe,OAAO,CAAC;AAAA,EAC1C;AAEA,SAAO;AACT;AAEO,IAAM,uBAAuB,CAAC,YACnC,cAAc,OAAO;AAEhB,IAAM,oBAAoB,CAAC,SAChC,cAAc,IAAI;;;ACnCpB,IAAM,kBAAkB,OAAO,IAAI,kCAAkC;AACrE,IAAM,eAAe,OAAO,IAAI,+BAA+B;AAC/D,IAAM,kBAAkB,OAAO,IAAI,kCAAkC;AACrE,IAAM,kBAAkB,OAAO,IAAI,kCAAkC;AACrE,IAAM,uBAAuB,OAAO,IAAI,sCAAsC;AAE9E,SAAS,qBACP,QACA,KACA,OACM;AACN,SAAO,eAAe,QAA6B,KAAK;AAAA,IACtD,cAAc;AAAA,IACd,YAAY;AAAA,IACZ;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AACH;AAEO,SAAS,eAAkC,SAAe;AAC/D,MACG,QAAuD,eAAe,GACvE;AACA,WAAO;AAAA,EACT;AAEA,uBAAqB,SAAS,WAAW,qBAAqB,OAAO,CAAC;AAEtE,uBAAqB,SAAS,iBAAiB,IAAI;AAEnD,SAAO;AACT;AAEO,SAAS,YAA4B,MAAY;AACtD,MAAK,KAAiD,YAAY,GAAG;AACnE,WAAO;AAAA,EACT;AAEA,QAAM,kBAAmB,KAAa,QAAQ,KAAK,IAAI;AACvD,EAAC,KAAa,UAAW,IAAI,SAAgB;AAC3C,UAAM,UAAU,gBAAgB,GAAG,IAAI;AACvC,WAAO,eAAe,OAAO;AAAA,EAC/B;AAEA,uBAAqB,MAAM,WAAW,kBAAkB,IAAI,CAAC;AAC7D,uBAAqB,MAAM,cAAc,IAAI;AAE7C,SAAO;AACT;AAEO,SAAS,sBAAgD,SAAe;AAC7E,MACG,QAAuD,eAAe,GACvE;AACA,WAAO;AAAA,EACT;AAEA,QAAM,kBAAmB,QAAgB,QAAQ,KAAK,OAAO;AAC7D,EAAC,QAAgB,UAAW,UAAU,SAAgB;AACpD,UAAM,OAAO,MAAM,gBAAgB,GAAG,IAAI;AAC1C,WAAO,YAAY,IAAI;AAAA,EACzB;AAEA,QAAM,gBAAiB,QAAgB,OAAO,KAAK,OAAO;AAC1D,MAAI,eAAe;AACjB,IAAC,QAAgB,QAAS,MACxB,cAAc,EAAE,IAAI,CAAC,SAAe,YAAY,IAAI,CAAC;AAAA,EACzD;AAEA,MAAI,CAAE,QAA8C,UAAU;AAC5D,yBAAqB,SAAS,YAAY,MAAM;AAC9C,aAAO,eAAe,OAAO;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,uBAAqB,SAAS,iBAAiB,IAAI;AAEnD,SAAO;AACT;AAEO,SAAS,eAAkC,SAAe;AAC/D,MACG,QAAuD,eAAe,GACvE;AACA,WAAO;AAAA,EACT;AAEA,QAAM,qBAAsB,QAAgB,WAAW,KAAK,OAAO;AACnE,EAAC,QAAgB,aAAc,UAAU,SAAgB;AACvD,UAAM,UAAU,MAAM,mBAAmB,GAAG,IAAI;AAChD,WAAO,sBAAsB,OAAO;AAAA,EACtC;AAEA,QAAM,kBAAmB,QAAgB,QAAQ,KAAK,OAAO;AAC7D,EAAC,QAAgB,UAAW,UAAU,SAAgB;AACpD,UAAM,OAAO,MAAM,gBAAgB,GAAG,IAAI;AAC1C,WAAO,YAAY,IAAI;AAAA,EACzB;AAEA,QAAM,mBAAoB,QAAgB,SAAS,KAAK,OAAO;AAC/D,EAAC,QAAgB,WAAY,MAC3B,iBAAiB,EAAE;AAAA,IAAI,CAAC,YACtB,sBAAsB,OAAO;AAAA,EAC/B;AAEF,MAAI,CAAE,QAA8C,UAAU;AAC5D,yBAAqB,SAAS,YAAY,MAAM;AAE9C,YAAM,WAAW,QAAQ,SAAS;AAClC,YAAM,UAAU,SAAS,SAAS,IAAI,SAAS,CAAC,IAAI,QAAQ,SAAS,EAAE,CAAC;AACxE,aAAO,eAAe,OAAO;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,uBAAqB,SAAS,iBAAiB,IAAI;AAEnD,SAAO;AACT;AAEO,SAAS,mBACd,aACuB;AACvB,MACG,YACC,oBACF,GACA;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAkB,YAAoB,OAAO,KAAK,WAAW;AACnE,EAAC,YAAoB,SAAU,UAC1B,SACA;AACH,UAAM,UAAU,MAAM,eAAe,GAAG,IAAI;AAC5C,WAAO,eAAe,OAAO;AAAA,EAC/B;AAEA,QAAM,kBAAmB,YAAoB,SAAS,KAAK,WAAW;AACtE,MAAI,iBAAiB;AACnB,IAAC,YAAoB,UAAW,UAC3B,SACA;AACH,YAAM,UAAU,MAAM,gBAAgB,GAAG,IAAI;AAC7C,aAAO,eAAe,OAAO;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,yBAA0B,YAAoB,gBAAgB;AAAA,IAClE;AAAA,EACF;AACA,MAAI,wBAAwB;AAC1B,IAAC,YAAoB,iBAAkB,UAClC,SACA;AACH,YAAM,UAAU,MAAM,uBAAuB,GAAG,IAAI;AACpD,aAAO,eAAe,OAAO;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,kCACJ,YACA,yBAAyB,KAAK,WAAW;AAC3C,MAAI,iCAAiC;AACnC,IAAC,YAAoB,0BAA2B,UAC3C,SAGA;AACH,YAAM,UAAU,MAAM,gCAAgC,GAAG,IAAI;AAC7D,aAAO,sBAAsB,OAAO;AAAA,IACtC;AAAA,EAGF;AAEA,uBAAqB,aAAa,sBAAsB,IAAI;AAE5D,SAAO;AACT;","names":["png","test","STABLY_API_URL","alias","test","test","STABLY_API_URL","test"]}
1
+ {"version":3,"sources":["../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({\n pageMetadata: isPage(target)\n ? { title: await target.title(), url: target.url() }\n : undefined,\n prompt: condition,\n screenshot,\n });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v2/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n pageMetadata,\n prompt,\n screenshot,\n}: {\n pageMetadata?: { title: string; url: string };\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n\n const metadata = {\n prompt,\n ...(pageMetadata?.title ? { pageTitle: pageMetadata.title } : {}),\n ...(pageMetadata?.url ? { pageUrl: pageMetadata.url } : {}),\n };\n form.append(\"metadata\", JSON.stringify(metadata));\n\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"screenshot\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves when the agent successfully completes the task\n * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * // Handling failures with try-catch\n * try {\n * await agent.act('Complete the task', { page });\n * console.log('Agent completed the task successfully');\n * } catch (error) {\n * console.error('Agent failed:', error.message);\n * }\n * ```\n */\n async act(prompt: string, options: AgentActOptions): Promise<void> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let failureReason: string | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`,\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content?.trim())\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n // Only attach if there's actual reasoning content\n if (reasoningText) {\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n },\n );\n }\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n failureReason: maybeFailureReason,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n failureReason = maybeFailureReason ?? failureReason;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n const success = finalSuccess ?? false;\n if (!success) {\n throw new Error(failureReason ?? \"Agent failed to complete the task\");\n }\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n failureReason?: string;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n failureReason: success ? undefined : reason,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":"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","names":["png","test","STABLY_API_URL","alias","test","test","STABLY_API_URL","test"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stablyai/playwright-base",
3
- "version": "2.0.0-next.1",
3
+ "version": "2.0.0",
4
4
  "description": "Shared augmentation runtime for Stably Playwright wrappers",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",