@stablyai/playwright-base 2.0.5 → 2.0.6
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 +26 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +26 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -71,7 +71,7 @@ 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.
|
|
74
|
+
"X-Client-Version": "2.0.6"
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
// src/ai/verify-prompt.ts
|
|
@@ -477,6 +477,7 @@ var stablyPlaywrightMatchers = {
|
|
|
477
477
|
|
|
478
478
|
// src/playwright-augment/methods/agent.ts
|
|
479
479
|
var import_test2 = require("@playwright/test");
|
|
480
|
+
var import_p_retry = __toESM(require("p-retry"));
|
|
480
481
|
|
|
481
482
|
// src/utils/truncate.ts
|
|
482
483
|
var truncate = (inp, length) => inp.length <= length || inp.length <= 3 ? inp : `${inp.slice(0, length - 3)}...`;
|
|
@@ -790,23 +791,31 @@ var Agent = class {
|
|
|
790
791
|
}
|
|
791
792
|
const agentResponses = await import_test2.test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {
|
|
792
793
|
const screenshot = await takeStableScreenshot(activePage);
|
|
793
|
-
const response = await
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
794
|
+
const response = await (0, import_p_retry.default)(
|
|
795
|
+
() => fetch(AGENT_ENDPOINT, {
|
|
796
|
+
body: constructAgentPayload({
|
|
797
|
+
activePage,
|
|
798
|
+
additionalContext: newPageOpenedMsg ? { newPageMessage: newPageOpenedMsg } : void 0,
|
|
799
|
+
isError: agentMessage.isError,
|
|
800
|
+
message: agentMessage.message,
|
|
801
|
+
model: options.model,
|
|
802
|
+
screenshot,
|
|
803
|
+
sessionId,
|
|
804
|
+
tabManager
|
|
805
|
+
}),
|
|
806
|
+
headers: {
|
|
807
|
+
...SDK_METADATA_HEADERS,
|
|
808
|
+
Authorization: `Bearer ${apiKey}`
|
|
809
|
+
},
|
|
810
|
+
method: "POST"
|
|
803
811
|
}),
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
812
|
+
{
|
|
813
|
+
// Exponential backoff with jitter: ~2-4s, ~4-8s, ~8-16s
|
|
814
|
+
minTimeout: 2e3,
|
|
815
|
+
randomize: true,
|
|
816
|
+
retries: 3
|
|
817
|
+
}
|
|
818
|
+
);
|
|
810
819
|
newPageOpenedMsg = void 0;
|
|
811
820
|
const responseJson = await response.json();
|
|
812
821
|
if (!response.ok) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -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/scroll-helper.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\nconst MAX_ATTACHMENT_NAME_LENGTH = 80;\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 const sanitizedName =\n condition\n .trim()\n .toLowerCase()\n .replace(/[^\\w]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, MAX_ATTACHMENT_NAME_LENGTH) || \"toMatchScreenshotPrompt\";\n\n testInfo.attachments.push(\n {\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: `${sanitizedName}-reasoning`,\n },\n {\n body: screenshot,\n // Use binary type to avoid inline previews in the report\n // Ensures the screenshot is paired with the reasoning attachment instead of being rendered in a separate section.\n contentType: \"application/octet-stream\",\n name: `${sanitizedName}-screenshot.png`,\n },\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 { Page } from \"@playwright/test\";\n\ntype ScrollDirection = \"up\" | \"down\" | \"left\" | \"right\";\n\n/**\n * Attempts to scroll by finding the scrollable ancestor of the element at the given position.\n * Falls back to mouse.wheel() if no scrollable container is found.\n */\nexport async function scrollAtPosition({\n amount,\n direction,\n page,\n x,\n y,\n}: {\n amount: number;\n direction: ScrollDirection;\n page: Page;\n x: number;\n y: number;\n}): Promise<void> {\n const deltaX =\n direction === \"left\" ? -amount : direction === \"right\" ? amount : 0;\n const deltaY =\n direction === \"up\" ? -amount : direction === \"down\" ? amount : 0;\n // First try to scroll the element at the position directly (for scrollable containers)\n // Uses findAndScrollAncestor pattern - walks up DOM to find scrollable container\n const scrolled = await page.evaluate(\n ({ posX, posY, scrollDeltaX, scrollDeltaY }) => {\n const element = document.elementFromPoint(posX, posY);\n if (!element) {\n return false;\n }\n\n // Walk up the DOM tree to find a scrollable container\n let scrollableEl: Element | null = element;\n while (scrollableEl && scrollableEl !== document.documentElement) {\n const { overflowX, overflowY } = window.getComputedStyle(scrollableEl);\n const isScrollableX =\n scrollableEl.scrollWidth > scrollableEl.clientWidth &&\n (overflowX === \"auto\" || overflowX === \"scroll\");\n const isScrollableY =\n scrollableEl.scrollHeight > scrollableEl.clientHeight &&\n (overflowY === \"auto\" || overflowY === \"scroll\");\n if (isScrollableX || isScrollableY) {\n scrollableEl.scrollBy(scrollDeltaX, scrollDeltaY);\n return true;\n }\n scrollableEl = scrollableEl.parentElement;\n }\n return false;\n },\n { posX: x, posY: y, scrollDeltaX: deltaX, scrollDeltaY: deltaY },\n );\n\n if (!scrolled) {\n // Fall back to mouse.wheel() for page-level scrolling\n // Note: mouse.wheel() dispatches a wheel event at the mouse position, but the browser\n // decides how to handle it. It may not scroll if the element under the cursor isn't\n // scrollable, or may scroll a different container than expected.\n await page.mouse.move(x, y);\n await page.mouse.wheel(deltaX, deltaY);\n }\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport { scrollAtPosition } from \"./scroll-helper\";\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 scrollAtPosition({\n amount: agentResponse.scroll_amount,\n direction: agentResponse.scroll_direction,\n page: activePage,\n x,\n y,\n });\n\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"]}
|
|
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/scroll-helper.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\nconst MAX_ATTACHMENT_NAME_LENGTH = 80;\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 const sanitizedName =\n condition\n .trim()\n .toLowerCase()\n .replace(/[^\\w]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, MAX_ATTACHMENT_NAME_LENGTH) || \"toMatchScreenshotPrompt\";\n\n testInfo.attachments.push(\n {\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: `${sanitizedName}-reasoning`,\n },\n {\n body: screenshot,\n // Use binary type to avoid inline previews in the report\n // Ensures the screenshot is paired with the reasoning attachment instead of being rendered in a separate section.\n contentType: \"application/octet-stream\",\n name: `${sanitizedName}-screenshot.png`,\n },\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\";\nimport pRetry from \"p-retry\";\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 pRetry(\n () =>\n 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 // Exponential backoff with jitter: ~2-4s, ~4-8s, ~8-16s\n minTimeout: 2000,\n randomize: true,\n retries: 3,\n },\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 { Page } from \"@playwright/test\";\n\ntype ScrollDirection = \"up\" | \"down\" | \"left\" | \"right\";\n\n/**\n * Attempts to scroll by finding the scrollable ancestor of the element at the given position.\n * Falls back to mouse.wheel() if no scrollable container is found.\n */\nexport async function scrollAtPosition({\n amount,\n direction,\n page,\n x,\n y,\n}: {\n amount: number;\n direction: ScrollDirection;\n page: Page;\n x: number;\n y: number;\n}): Promise<void> {\n const deltaX =\n direction === \"left\" ? -amount : direction === \"right\" ? amount : 0;\n const deltaY =\n direction === \"up\" ? -amount : direction === \"down\" ? amount : 0;\n // First try to scroll the element at the position directly (for scrollable containers)\n // Uses findAndScrollAncestor pattern - walks up DOM to find scrollable container\n const scrolled = await page.evaluate(\n ({ posX, posY, scrollDeltaX, scrollDeltaY }) => {\n const element = document.elementFromPoint(posX, posY);\n if (!element) {\n return false;\n }\n\n // Walk up the DOM tree to find a scrollable container\n let scrollableEl: Element | null = element;\n while (scrollableEl && scrollableEl !== document.documentElement) {\n const { overflowX, overflowY } = window.getComputedStyle(scrollableEl);\n const isScrollableX =\n scrollableEl.scrollWidth > scrollableEl.clientWidth &&\n (overflowX === \"auto\" || overflowX === \"scroll\");\n const isScrollableY =\n scrollableEl.scrollHeight > scrollableEl.clientHeight &&\n (overflowY === \"auto\" || overflowY === \"scroll\");\n if (isScrollableX || isScrollableY) {\n scrollableEl.scrollBy(scrollDeltaX, scrollDeltaY);\n return true;\n }\n scrollableEl = scrollableEl.parentElement;\n }\n return false;\n },\n { posX: x, posY: y, scrollDeltaX: deltaX, scrollDeltaY: deltaY },\n );\n\n if (!scrolled) {\n // Fall back to mouse.wheel() for page-level scrolling\n // Note: mouse.wheel() dispatches a wheel event at the mouse position, but the browser\n // decides how to handle it. It may not scroll if the element under the cursor isn't\n // scrollable, or may scroll a different container than expected.\n await page.mouse.move(x, y);\n await page.mouse.wheel(deltaX, deltaY);\n }\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport { scrollAtPosition } from \"./scroll-helper\";\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 scrollAtPosition({\n amount: agentResponse.scroll_amount,\n direction: agentResponse.scroll_direction,\n page: activePage,\n x,\n y,\n });\n\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","pRetry","import_test","STABLY_API_URL"]}
|
package/dist/index.mjs
CHANGED
|
@@ -34,7 +34,7 @@ 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.
|
|
37
|
+
"X-Client-Version": "2.0.6"
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
// src/ai/verify-prompt.ts
|
|
@@ -440,6 +440,7 @@ var stablyPlaywrightMatchers = {
|
|
|
440
440
|
|
|
441
441
|
// src/playwright-augment/methods/agent.ts
|
|
442
442
|
import { test as test2 } from "@playwright/test";
|
|
443
|
+
import pRetry from "p-retry";
|
|
443
444
|
|
|
444
445
|
// src/utils/truncate.ts
|
|
445
446
|
var truncate = (inp, length) => inp.length <= length || inp.length <= 3 ? inp : `${inp.slice(0, length - 3)}...`;
|
|
@@ -753,23 +754,31 @@ var Agent = class {
|
|
|
753
754
|
}
|
|
754
755
|
const agentResponses = await test2.step(`[Thinking ${i + 1}]`, async (stepInfo) => {
|
|
755
756
|
const screenshot = await takeStableScreenshot(activePage);
|
|
756
|
-
const response = await
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
757
|
+
const response = await pRetry(
|
|
758
|
+
() => fetch(AGENT_ENDPOINT, {
|
|
759
|
+
body: constructAgentPayload({
|
|
760
|
+
activePage,
|
|
761
|
+
additionalContext: newPageOpenedMsg ? { newPageMessage: newPageOpenedMsg } : void 0,
|
|
762
|
+
isError: agentMessage.isError,
|
|
763
|
+
message: agentMessage.message,
|
|
764
|
+
model: options.model,
|
|
765
|
+
screenshot,
|
|
766
|
+
sessionId,
|
|
767
|
+
tabManager
|
|
768
|
+
}),
|
|
769
|
+
headers: {
|
|
770
|
+
...SDK_METADATA_HEADERS,
|
|
771
|
+
Authorization: `Bearer ${apiKey}`
|
|
772
|
+
},
|
|
773
|
+
method: "POST"
|
|
766
774
|
}),
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
775
|
+
{
|
|
776
|
+
// Exponential backoff with jitter: ~2-4s, ~4-8s, ~8-16s
|
|
777
|
+
minTimeout: 2e3,
|
|
778
|
+
randomize: true,
|
|
779
|
+
retries: 3
|
|
780
|
+
}
|
|
781
|
+
);
|
|
773
782
|
newPageOpenedMsg = void 0;
|
|
774
783
|
const responseJson = await response.json();
|
|
775
784
|
if (!response.ok) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -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/scroll-helper.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\nconst MAX_ATTACHMENT_NAME_LENGTH = 80;\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 const sanitizedName =\n condition\n .trim()\n .toLowerCase()\n .replace(/[^\\w]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, MAX_ATTACHMENT_NAME_LENGTH) || \"toMatchScreenshotPrompt\";\n\n testInfo.attachments.push(\n {\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: `${sanitizedName}-reasoning`,\n },\n {\n body: screenshot,\n // Use binary type to avoid inline previews in the report\n // Ensures the screenshot is paired with the reasoning attachment instead of being rendered in a separate section.\n contentType: \"application/octet-stream\",\n name: `${sanitizedName}-screenshot.png`,\n },\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 { Page } from \"@playwright/test\";\n\ntype ScrollDirection = \"up\" | \"down\" | \"left\" | \"right\";\n\n/**\n * Attempts to scroll by finding the scrollable ancestor of the element at the given position.\n * Falls back to mouse.wheel() if no scrollable container is found.\n */\nexport async function scrollAtPosition({\n amount,\n direction,\n page,\n x,\n y,\n}: {\n amount: number;\n direction: ScrollDirection;\n page: Page;\n x: number;\n y: number;\n}): Promise<void> {\n const deltaX =\n direction === \"left\" ? -amount : direction === \"right\" ? amount : 0;\n const deltaY =\n direction === \"up\" ? -amount : direction === \"down\" ? amount : 0;\n // First try to scroll the element at the position directly (for scrollable containers)\n // Uses findAndScrollAncestor pattern - walks up DOM to find scrollable container\n const scrolled = await page.evaluate(\n ({ posX, posY, scrollDeltaX, scrollDeltaY }) => {\n const element = document.elementFromPoint(posX, posY);\n if (!element) {\n return false;\n }\n\n // Walk up the DOM tree to find a scrollable container\n let scrollableEl: Element | null = element;\n while (scrollableEl && scrollableEl !== document.documentElement) {\n const { overflowX, overflowY } = window.getComputedStyle(scrollableEl);\n const isScrollableX =\n scrollableEl.scrollWidth > scrollableEl.clientWidth &&\n (overflowX === \"auto\" || overflowX === \"scroll\");\n const isScrollableY =\n scrollableEl.scrollHeight > scrollableEl.clientHeight &&\n (overflowY === \"auto\" || overflowY === \"scroll\");\n if (isScrollableX || isScrollableY) {\n scrollableEl.scrollBy(scrollDeltaX, scrollDeltaY);\n return true;\n }\n scrollableEl = scrollableEl.parentElement;\n }\n return false;\n },\n { posX: x, posY: y, scrollDeltaX: deltaX, scrollDeltaY: deltaY },\n );\n\n if (!scrolled) {\n // Fall back to mouse.wheel() for page-level scrolling\n // Note: mouse.wheel() dispatches a wheel event at the mouse position, but the browser\n // decides how to handle it. It may not scroll if the element under the cursor isn't\n // scrollable, or may scroll a different container than expected.\n await page.mouse.move(x, y);\n await page.mouse.wheel(deltaX, deltaY);\n }\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport { scrollAtPosition } from \"./scroll-helper\";\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 scrollAtPosition({\n amount: agentResponse.scroll_amount,\n direction: agentResponse.scroll_direction,\n page: activePage,\n x,\n y,\n });\n\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"]}
|
|
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/scroll-helper.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\nconst MAX_ATTACHMENT_NAME_LENGTH = 80;\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 const sanitizedName =\n condition\n .trim()\n .toLowerCase()\n .replace(/[^\\w]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, MAX_ATTACHMENT_NAME_LENGTH) || \"toMatchScreenshotPrompt\";\n\n testInfo.attachments.push(\n {\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: `${sanitizedName}-reasoning`,\n },\n {\n body: screenshot,\n // Use binary type to avoid inline previews in the report\n // Ensures the screenshot is paired with the reasoning attachment instead of being rendered in a separate section.\n contentType: \"application/octet-stream\",\n name: `${sanitizedName}-screenshot.png`,\n },\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\";\nimport pRetry from \"p-retry\";\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 pRetry(\n () =>\n 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 // Exponential backoff with jitter: ~2-4s, ~4-8s, ~8-16s\n minTimeout: 2000,\n randomize: true,\n retries: 3,\n },\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 { Page } from \"@playwright/test\";\n\ntype ScrollDirection = \"up\" | \"down\" | \"left\" | \"right\";\n\n/**\n * Attempts to scroll by finding the scrollable ancestor of the element at the given position.\n * Falls back to mouse.wheel() if no scrollable container is found.\n */\nexport async function scrollAtPosition({\n amount,\n direction,\n page,\n x,\n y,\n}: {\n amount: number;\n direction: ScrollDirection;\n page: Page;\n x: number;\n y: number;\n}): Promise<void> {\n const deltaX =\n direction === \"left\" ? -amount : direction === \"right\" ? amount : 0;\n const deltaY =\n direction === \"up\" ? -amount : direction === \"down\" ? amount : 0;\n // First try to scroll the element at the position directly (for scrollable containers)\n // Uses findAndScrollAncestor pattern - walks up DOM to find scrollable container\n const scrolled = await page.evaluate(\n ({ posX, posY, scrollDeltaX, scrollDeltaY }) => {\n const element = document.elementFromPoint(posX, posY);\n if (!element) {\n return false;\n }\n\n // Walk up the DOM tree to find a scrollable container\n let scrollableEl: Element | null = element;\n while (scrollableEl && scrollableEl !== document.documentElement) {\n const { overflowX, overflowY } = window.getComputedStyle(scrollableEl);\n const isScrollableX =\n scrollableEl.scrollWidth > scrollableEl.clientWidth &&\n (overflowX === \"auto\" || overflowX === \"scroll\");\n const isScrollableY =\n scrollableEl.scrollHeight > scrollableEl.clientHeight &&\n (overflowY === \"auto\" || overflowY === \"scroll\");\n if (isScrollableX || isScrollableY) {\n scrollableEl.scrollBy(scrollDeltaX, scrollDeltaY);\n return true;\n }\n scrollableEl = scrollableEl.parentElement;\n }\n return false;\n },\n { posX: x, posY: y, scrollDeltaX: deltaX, scrollDeltaY: deltaY },\n );\n\n if (!scrolled) {\n // Fall back to mouse.wheel() for page-level scrolling\n // Note: mouse.wheel() dispatches a wheel event at the mouse position, but the browser\n // decides how to handle it. It may not scroll if the element under the cursor isn't\n // scrollable, or may scroll a different container than expected.\n await page.mouse.move(x, y);\n await page.mouse.wheel(deltaX, deltaY);\n }\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport { scrollAtPosition } from \"./scroll-helper\";\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 scrollAtPosition({\n amount: agentResponse.scroll_amount,\n direction: agentResponse.scroll_direction,\n page: activePage,\n x,\n y,\n });\n\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.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Shared augmentation runtime for Stably Playwright wrappers",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"jpeg-js": "0.4.4",
|
|
28
|
+
"p-retry": "^7.1.1",
|
|
28
29
|
"pixelmatch": "7.1.0",
|
|
29
30
|
"pngjs": "7.0.0"
|
|
30
31
|
},
|