@stablyai/playwright-base 0.1.8 → 0.1.10
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 +2 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -67,7 +67,7 @@ var isObject = (value) => {
|
|
|
67
67
|
// src/ai/metadata.ts
|
|
68
68
|
var SDK_METADATA_HEADERS = {
|
|
69
69
|
"X-Client-Name": "stably-playwright-sdk-js",
|
|
70
|
-
"X-Client-Version": "0.1.
|
|
70
|
+
"X-Client-Version": "0.1.10"
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
// src/ai/extract.ts
|
|
@@ -690,8 +690,7 @@ function augmentLocator(locator) {
|
|
|
690
690
|
if (typeof locator.describe === "function" && !markerTarget[LOCATOR_DESCRIBE_WRAPPED]) {
|
|
691
691
|
const originalDescribe = locator.describe.bind(locator);
|
|
692
692
|
locator.describe = (description, options) => {
|
|
693
|
-
|
|
694
|
-
const result = originalDescribe(description);
|
|
693
|
+
const result = originalDescribe(description, options);
|
|
695
694
|
return result ? augmentLocator(result) : result;
|
|
696
695
|
};
|
|
697
696
|
defineHiddenProperty(locator, LOCATOR_DESCRIBE_WRAPPED, true);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/methods/agent.ts","../src/playwright-type-predicates.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/image-compare.ts","../src/screenshot.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/augment.ts","../src/ai/verify-prompt.ts","../src/expect.ts"],"sourcesContent":["import type { Page } from \"@stablyai/internal-playwright-test\";\nimport type { LocatorDescribeOptions } from \"./playwright-augment/augment\";\nimport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\n\nimport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n} from \"./playwright-augment/augment\";\nimport { stablyPlaywrightMatchers } from \"./expect\";\nimport { requireApiKey } from \"./runtime\";\n\nexport { setApiKey } from \"./runtime\";\n\nexport type { LocatorDescribeOptions } from \"./playwright-augment/augment\";\nexport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\nexport type ScreenshotPromptOptions =\n import(\"@stablyai/internal-playwright-test\").PageAssertionsToHaveScreenshotOptions;\nexport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n stablyPlaywrightMatchers,\n requireApiKey,\n};\n\nexport interface Expect<T = Page> {\n toMatchScreenshotPrompt(\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<void>;\n}\n\ndeclare module \"@stablyai/internal-playwright-test\" {\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 describe(description: string, options?: LocatorDescribeOptions): Locator;\n }\n\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 interface BrowserContext {\n agent(\n prompt: string,\n options: { page: Page; maxCycles?: number },\n ): Promise<{ success: boolean }>;\n }\n\n interface Browser {\n agent(\n prompt: string,\n options: { page: Page; maxCycles?: number },\n ): Promise<{ success: boolean }>;\n }\n}\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 type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type * as z4 from \"zod/v4/core\";\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport interface ExtractSchema extends z4.$ZodType {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n ): Promise<z4.util.SafeParseResult<z4.output<this>>>;\n}\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_ENDPOINT = \"https://api.stably.ai/internal/v2/extract\";\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\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: ReadonlyArray<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(\"Validation failed\", result.error.issues);\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 prompt,\n pageOrLocator,\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 schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\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 const pngBuffer = await pageOrLocator.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 method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\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 === false) {\n return raw.error;\n }\n\n const { value } = raw;\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\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 prompt,\n schema: options.schema,\n pageOrLocator,\n });\n }\n\n return extract({ prompt, pageOrLocator });\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","import type { Page } from \"@stablyai/internal-playwright-test\";\nimport { test } from \"@stablyai/internal-playwright-test\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentResponse } from \"./agent/tool-responses\";\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\n\ntype AgentOptions = {\n page: Page;\n maxCycles?: number;\n};\n\ntype AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\nconst AGENT_PATH = \"internal/v1/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\nexport function createAgentStub(): (\n prompt: string,\n options: AgentOptions,\n) => Promise<{ success: boolean }> {\n return async (prompt: string, options: AgentOptions) => {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n const browserContext = options.page.context();\n\n const tabManager = new Map<Page, string>();\n browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n message: prompt,\n isError: false,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n browserContext.on(\"page\", onNewPage);\n\n return await test.step(prompt, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: constructAgentPayload({\n sessionId,\n message: agentMessage.message,\n isError: agentMessage.isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\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 const agentResponse = responseJson as AgentResponse;\n\n agentMessage = await (async () => {\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { message: `pressed \"${text}\"` };\n }\n return { message: \"pressed key\" };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { message: `typed \"${text}\"` };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { message: `mouse moved to [${x}, ${y}]` };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { message: `left click at [${x}, ${y}]` };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { message: `right click at [${x}, ${y}]` };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { message: `double click at [${x}, ${y}]` };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { message: `triple click at [${x}, ${y}]` };\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 {\n message: `dragged from [${startX}, ${startY}] to [${endX}, ${endY}]`,\n };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { message: \"captured screenshot\" };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? 3000;\n await activePage.waitForTimeout(waitMs);\n return { message: `waited ${waitMs}ms` };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return { message: `navigated to \"${agentResponse.url}\"` };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n return { 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 message: `switched to \"${agentResponse.tab_alias}\"`,\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n 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 return { message: \"navigated back\" };\n }\n case \"terminate_test\": {\n const { success, reason } = agentResponse;\n finalSuccess = success;\n return { message: reason, shouldTerminate: true };\n }\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n return { message, isError: true };\n }\n })();\n }\n } finally {\n browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n };\n}\n","import { Page, Locator } from \"@stablyai/internal-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","/**\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","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\nimport * as jpeg from \"jpeg-js\";\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, width: png.width, height: png.height };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, width: img.width, height: img.height };\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, width: png.width, height: png.height };\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\nimport { isPage } from \"./playwright-type-predicates\";\nimport { imagesAreSimilar } from \"./image-compare\";\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) break;\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 { Page } from \"@stablyai/internal-playwright-test\";\n\nexport function constructAgentPayload({\n sessionId,\n message,\n isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext,\n}: {\n sessionId: string;\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 form.append(\"session_id\", sessionId);\n form.append(\"message\", message);\n if (isError) {\n form.append(\"is_error\", JSON.stringify(isError));\n }\n if (additionalContext) {\n form.append(\"additional_context\", JSON.stringify(additionalContext));\n }\n\n const viewportSize = activePage.viewportSize();\n if (viewportSize) {\n form.append(\"page_dimensions\", JSON.stringify(viewportSize));\n }\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 const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n form.append(\"all_pages\", JSON.stringify(tabs));\n\n const activePageAlias = tabManager.get(activePage);\n if (activePageAlias) {\n form.append(\"active_page_alias\", activePageAlias);\n }\n return form;\n}\n","import type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@stablyai/internal-playwright-test\";\n\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\nimport { createAgentStub } from \"./methods/agent\";\n\nexport interface LocatorDescribeOptions {\n autoHeal?: boolean;\n}\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst LOCATOR_DESCRIBE_WRAPPED = Symbol.for(\n \"stably.playwright.locatorDescribeWrapped\",\n);\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 value,\n enumerable: false,\n configurable: true,\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 const markerTarget = locator as unknown as Record<PropertyKey, unknown>;\n\n if (\n typeof locator.describe === \"function\" &&\n !markerTarget[LOCATOR_DESCRIBE_WRAPPED]\n ) {\n const originalDescribe = locator.describe.bind(locator);\n locator.describe = ((\n description: string,\n options?: LocatorDescribeOptions,\n ) => {\n void options;\n const result = originalDescribe(description);\n return result ? augmentLocator(result as Locator) : result;\n }) as Locator[\"describe\"];\n\n defineHiddenProperty(locator, LOCATOR_DESCRIBE_WRAPPED, true);\n }\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.locator.bind(page);\n page.locator = ((...args: Parameters<Page[\"locator\"]>) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as Page[\"locator\"];\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.newPage.bind(context);\n context.newPage = (async (...args: Parameters<BrowserContext[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as BrowserContext[\"newPage\"];\n\n const originalPages = context.pages?.bind(context);\n if (originalPages) {\n context.pages = (() =>\n originalPages().map((page) =>\n augmentPage(page),\n )) as BrowserContext[\"pages\"];\n }\n\n if (!(context as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(context, \"agent\", createAgentStub());\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.newContext.bind(browser);\n browser.newContext = (async (...args: Parameters<Browser[\"newContext\"]>) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as Browser[\"newContext\"];\n\n const originalNewPage = browser.newPage.bind(browser);\n browser.newPage = (async (...args: Parameters<Browser[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as Browser[\"newPage\"];\n\n const originalContexts = browser.contexts.bind(browser);\n browser.contexts = (() =>\n originalContexts().map((context) =>\n augmentBrowserContext(context),\n )) as Browser[\"contexts\"];\n\n if (!(browser as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(browser, \"agent\", createAgentStub());\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.launch.bind(browserType);\n browserType.launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser);\n }) as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = browserType.connect?.bind(browserType);\n if (originalConnect) {\n browserType.connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = browserType.connectOverCDP?.bind(browserType);\n if (originalConnectOverCDP) {\n browserType.connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext =\n browserType.launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n browserType.launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context);\n }) as NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n","import { isObject } from \"../type-predicate/is-object\";\nimport { requireApiKey } from \"../runtime\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_ENDPOINT = \"https://api.stably.ai/internal/v1/assert\";\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 { success, reason } = 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 success,\n reason,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { success, reason } = 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 { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n targetType,\n condition,\n didPass,\n isNot,\n reason,\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 ) {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n return {\n pass: verifyResult.pass,\n message: () =>\n createFailureMessage({\n targetType,\n condition,\n didPass: verifyResult.pass,\n reason: verifyResult.reason,\n isNot: this.isNot,\n }),\n };\n },\n} as const;\n"],"mappings":"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","names":["png","alias"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/methods/agent.ts","../src/playwright-type-predicates.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/image-compare.ts","../src/screenshot.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/augment.ts","../src/ai/verify-prompt.ts","../src/expect.ts"],"sourcesContent":["import type { Page } from \"@stablyai/internal-playwright-test\";\nimport type { LocatorDescribeOptions } from \"./playwright-augment/augment\";\nimport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\n\nimport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n} from \"./playwright-augment/augment\";\nimport { stablyPlaywrightMatchers } from \"./expect\";\nimport { requireApiKey } from \"./runtime\";\n\nexport { setApiKey } from \"./runtime\";\n\nexport type { LocatorDescribeOptions } from \"./playwright-augment/augment\";\nexport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\nexport type ScreenshotPromptOptions =\n import(\"@stablyai/internal-playwright-test\").PageAssertionsToHaveScreenshotOptions;\nexport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n stablyPlaywrightMatchers,\n requireApiKey,\n};\n\nexport interface Expect<T = Page> {\n toMatchScreenshotPrompt(\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<void>;\n}\n\ndeclare module \"@stablyai/internal-playwright-test\" {\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 describe(description: string, options?: LocatorDescribeOptions): Locator;\n }\n\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 interface BrowserContext {\n agent(\n prompt: string,\n options: { page: Page; maxCycles?: number },\n ): Promise<{ success: boolean }>;\n }\n\n interface Browser {\n agent(\n prompt: string,\n options: { page: Page; maxCycles?: number },\n ): Promise<{ success: boolean }>;\n }\n}\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 type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type * as z4 from \"zod/v4/core\";\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport interface ExtractSchema extends z4.$ZodType {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n ): Promise<z4.util.SafeParseResult<z4.output<this>>>;\n}\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_ENDPOINT = \"https://api.stably.ai/internal/v2/extract\";\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\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: ReadonlyArray<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(\"Validation failed\", result.error.issues);\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 prompt,\n pageOrLocator,\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 schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\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 const pngBuffer = await pageOrLocator.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 method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\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 === false) {\n return raw.error;\n }\n\n const { value } = raw;\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\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 prompt,\n schema: options.schema,\n pageOrLocator,\n });\n }\n\n return extract({ prompt, pageOrLocator });\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","import type { Page } from \"@stablyai/internal-playwright-test\";\nimport { test } from \"@stablyai/internal-playwright-test\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentResponse } from \"./agent/tool-responses\";\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\n\ntype AgentOptions = {\n page: Page;\n maxCycles?: number;\n};\n\ntype AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\nconst AGENT_PATH = \"internal/v1/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\nexport function createAgentStub(): (\n prompt: string,\n options: AgentOptions,\n) => Promise<{ success: boolean }> {\n return async (prompt: string, options: AgentOptions) => {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n const browserContext = options.page.context();\n\n const tabManager = new Map<Page, string>();\n browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n message: prompt,\n isError: false,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n browserContext.on(\"page\", onNewPage);\n\n return await test.step(prompt, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: constructAgentPayload({\n sessionId,\n message: agentMessage.message,\n isError: agentMessage.isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\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 const agentResponse = responseJson as AgentResponse;\n\n agentMessage = await (async () => {\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { message: `pressed \"${text}\"` };\n }\n return { message: \"pressed key\" };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { message: `typed \"${text}\"` };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { message: `mouse moved to [${x}, ${y}]` };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { message: `left click at [${x}, ${y}]` };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { message: `right click at [${x}, ${y}]` };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { message: `double click at [${x}, ${y}]` };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { message: `triple click at [${x}, ${y}]` };\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 {\n message: `dragged from [${startX}, ${startY}] to [${endX}, ${endY}]`,\n };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { message: \"captured screenshot\" };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? 3000;\n await activePage.waitForTimeout(waitMs);\n return { message: `waited ${waitMs}ms` };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return { message: `navigated to \"${agentResponse.url}\"` };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n return { 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 message: `switched to \"${agentResponse.tab_alias}\"`,\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n 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 return { message: \"navigated back\" };\n }\n case \"terminate_test\": {\n const { success, reason } = agentResponse;\n finalSuccess = success;\n return { message: reason, shouldTerminate: true };\n }\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n return { message, isError: true };\n }\n })();\n }\n } finally {\n browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n };\n}\n","import { Page, Locator } from \"@stablyai/internal-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","/**\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","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\nimport * as jpeg from \"jpeg-js\";\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, width: png.width, height: png.height };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, width: img.width, height: img.height };\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, width: png.width, height: png.height };\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\nimport { isPage } from \"./playwright-type-predicates\";\nimport { imagesAreSimilar } from \"./image-compare\";\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) break;\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 { Page } from \"@stablyai/internal-playwright-test\";\n\nexport function constructAgentPayload({\n sessionId,\n message,\n isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext,\n}: {\n sessionId: string;\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 form.append(\"session_id\", sessionId);\n form.append(\"message\", message);\n if (isError) {\n form.append(\"is_error\", JSON.stringify(isError));\n }\n if (additionalContext) {\n form.append(\"additional_context\", JSON.stringify(additionalContext));\n }\n\n const viewportSize = activePage.viewportSize();\n if (viewportSize) {\n form.append(\"page_dimensions\", JSON.stringify(viewportSize));\n }\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 const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n form.append(\"all_pages\", JSON.stringify(tabs));\n\n const activePageAlias = tabManager.get(activePage);\n if (activePageAlias) {\n form.append(\"active_page_alias\", activePageAlias);\n }\n return form;\n}\n","import type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@stablyai/internal-playwright-test\";\n\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\nimport { createAgentStub } from \"./methods/agent\";\n\nexport interface LocatorDescribeOptions {\n autoHeal?: boolean;\n}\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst LOCATOR_DESCRIBE_WRAPPED = Symbol.for(\n \"stably.playwright.locatorDescribeWrapped\",\n);\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 value,\n enumerable: false,\n configurable: true,\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 const markerTarget = locator as unknown as Record<PropertyKey, unknown>;\n\n if (\n typeof locator.describe === \"function\" &&\n !markerTarget[LOCATOR_DESCRIBE_WRAPPED]\n ) {\n const originalDescribe = locator.describe.bind(locator);\n locator.describe = ((\n description: string,\n options?: LocatorDescribeOptions,\n ) => {\n const result = originalDescribe(description, options);\n return result ? augmentLocator(result as Locator) : result;\n }) as Locator[\"describe\"];\n\n defineHiddenProperty(locator, LOCATOR_DESCRIBE_WRAPPED, true);\n }\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.locator.bind(page);\n page.locator = ((...args: Parameters<Page[\"locator\"]>) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as Page[\"locator\"];\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.newPage.bind(context);\n context.newPage = (async (...args: Parameters<BrowserContext[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as BrowserContext[\"newPage\"];\n\n const originalPages = context.pages?.bind(context);\n if (originalPages) {\n context.pages = (() =>\n originalPages().map((page) =>\n augmentPage(page),\n )) as BrowserContext[\"pages\"];\n }\n\n if (!(context as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(context, \"agent\", createAgentStub());\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.newContext.bind(browser);\n browser.newContext = (async (...args: Parameters<Browser[\"newContext\"]>) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as Browser[\"newContext\"];\n\n const originalNewPage = browser.newPage.bind(browser);\n browser.newPage = (async (...args: Parameters<Browser[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as Browser[\"newPage\"];\n\n const originalContexts = browser.contexts.bind(browser);\n browser.contexts = (() =>\n originalContexts().map((context) =>\n augmentBrowserContext(context),\n )) as Browser[\"contexts\"];\n\n if (!(browser as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(browser, \"agent\", createAgentStub());\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.launch.bind(browserType);\n browserType.launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser);\n }) as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = browserType.connect?.bind(browserType);\n if (originalConnect) {\n browserType.connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = browserType.connectOverCDP?.bind(browserType);\n if (originalConnectOverCDP) {\n browserType.connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext =\n browserType.launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n browserType.launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context);\n }) as NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n","import { isObject } from \"../type-predicate/is-object\";\nimport { requireApiKey } from \"../runtime\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_ENDPOINT = \"https://api.stably.ai/internal/v1/assert\";\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 { success, reason } = 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 success,\n reason,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { success, reason } = 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 { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n targetType,\n condition,\n didPass,\n isNot,\n reason,\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 ) {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n return {\n pass: verifyResult.pass,\n message: () =>\n createFailureMessage({\n targetType,\n condition,\n didPass: verifyResult.pass,\n reason: verifyResult.reason,\n isNot: this.isNot,\n }),\n };\n },\n} as const;\n"],"mappings":"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","names":["png","alias"]}
|
package/dist/index.mjs
CHANGED
|
@@ -31,7 +31,7 @@ var isObject = (value) => {
|
|
|
31
31
|
// src/ai/metadata.ts
|
|
32
32
|
var SDK_METADATA_HEADERS = {
|
|
33
33
|
"X-Client-Name": "stably-playwright-sdk-js",
|
|
34
|
-
"X-Client-Version": "0.1.
|
|
34
|
+
"X-Client-Version": "0.1.10"
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
// src/ai/extract.ts
|
|
@@ -654,8 +654,7 @@ function augmentLocator(locator) {
|
|
|
654
654
|
if (typeof locator.describe === "function" && !markerTarget[LOCATOR_DESCRIBE_WRAPPED]) {
|
|
655
655
|
const originalDescribe = locator.describe.bind(locator);
|
|
656
656
|
locator.describe = (description, options) => {
|
|
657
|
-
|
|
658
|
-
const result = originalDescribe(description);
|
|
657
|
+
const result = originalDescribe(description, options);
|
|
659
658
|
return result ? augmentLocator(result) : result;
|
|
660
659
|
};
|
|
661
660
|
defineHiddenProperty(locator, LOCATOR_DESCRIBE_WRAPPED, true);
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/methods/agent.ts","../src/playwright-type-predicates.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/image-compare.ts","../src/screenshot.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/augment.ts","../src/ai/verify-prompt.ts","../src/expect.ts"],"sourcesContent":["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 type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type * as z4 from \"zod/v4/core\";\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport interface ExtractSchema extends z4.$ZodType {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n ): Promise<z4.util.SafeParseResult<z4.output<this>>>;\n}\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_ENDPOINT = \"https://api.stably.ai/internal/v2/extract\";\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\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: ReadonlyArray<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(\"Validation failed\", result.error.issues);\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 prompt,\n pageOrLocator,\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 schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\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 const pngBuffer = await pageOrLocator.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 method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\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 === false) {\n return raw.error;\n }\n\n const { value } = raw;\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\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 prompt,\n schema: options.schema,\n pageOrLocator,\n });\n }\n\n return extract({ prompt, pageOrLocator });\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","import type { Page } from \"@stablyai/internal-playwright-test\";\nimport { test } from \"@stablyai/internal-playwright-test\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentResponse } from \"./agent/tool-responses\";\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\n\ntype AgentOptions = {\n page: Page;\n maxCycles?: number;\n};\n\ntype AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\nconst AGENT_PATH = \"internal/v1/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\nexport function createAgentStub(): (\n prompt: string,\n options: AgentOptions,\n) => Promise<{ success: boolean }> {\n return async (prompt: string, options: AgentOptions) => {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n const browserContext = options.page.context();\n\n const tabManager = new Map<Page, string>();\n browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n message: prompt,\n isError: false,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n browserContext.on(\"page\", onNewPage);\n\n return await test.step(prompt, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: constructAgentPayload({\n sessionId,\n message: agentMessage.message,\n isError: agentMessage.isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\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 const agentResponse = responseJson as AgentResponse;\n\n agentMessage = await (async () => {\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { message: `pressed \"${text}\"` };\n }\n return { message: \"pressed key\" };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { message: `typed \"${text}\"` };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { message: `mouse moved to [${x}, ${y}]` };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { message: `left click at [${x}, ${y}]` };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { message: `right click at [${x}, ${y}]` };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { message: `double click at [${x}, ${y}]` };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { message: `triple click at [${x}, ${y}]` };\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 {\n message: `dragged from [${startX}, ${startY}] to [${endX}, ${endY}]`,\n };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { message: \"captured screenshot\" };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? 3000;\n await activePage.waitForTimeout(waitMs);\n return { message: `waited ${waitMs}ms` };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return { message: `navigated to \"${agentResponse.url}\"` };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n return { 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 message: `switched to \"${agentResponse.tab_alias}\"`,\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n 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 return { message: \"navigated back\" };\n }\n case \"terminate_test\": {\n const { success, reason } = agentResponse;\n finalSuccess = success;\n return { message: reason, shouldTerminate: true };\n }\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n return { message, isError: true };\n }\n })();\n }\n } finally {\n browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n };\n}\n","import { Page, Locator } from \"@stablyai/internal-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","/**\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","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\nimport * as jpeg from \"jpeg-js\";\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, width: png.width, height: png.height };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, width: img.width, height: img.height };\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, width: png.width, height: png.height };\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\nimport { isPage } from \"./playwright-type-predicates\";\nimport { imagesAreSimilar } from \"./image-compare\";\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) break;\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 { Page } from \"@stablyai/internal-playwright-test\";\n\nexport function constructAgentPayload({\n sessionId,\n message,\n isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext,\n}: {\n sessionId: string;\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 form.append(\"session_id\", sessionId);\n form.append(\"message\", message);\n if (isError) {\n form.append(\"is_error\", JSON.stringify(isError));\n }\n if (additionalContext) {\n form.append(\"additional_context\", JSON.stringify(additionalContext));\n }\n\n const viewportSize = activePage.viewportSize();\n if (viewportSize) {\n form.append(\"page_dimensions\", JSON.stringify(viewportSize));\n }\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 const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n form.append(\"all_pages\", JSON.stringify(tabs));\n\n const activePageAlias = tabManager.get(activePage);\n if (activePageAlias) {\n form.append(\"active_page_alias\", activePageAlias);\n }\n return form;\n}\n","import type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@stablyai/internal-playwright-test\";\n\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\nimport { createAgentStub } from \"./methods/agent\";\n\nexport interface LocatorDescribeOptions {\n autoHeal?: boolean;\n}\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst LOCATOR_DESCRIBE_WRAPPED = Symbol.for(\n \"stably.playwright.locatorDescribeWrapped\",\n);\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 value,\n enumerable: false,\n configurable: true,\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 const markerTarget = locator as unknown as Record<PropertyKey, unknown>;\n\n if (\n typeof locator.describe === \"function\" &&\n !markerTarget[LOCATOR_DESCRIBE_WRAPPED]\n ) {\n const originalDescribe = locator.describe.bind(locator);\n locator.describe = ((\n description: string,\n options?: LocatorDescribeOptions,\n ) => {\n void options;\n const result = originalDescribe(description);\n return result ? augmentLocator(result as Locator) : result;\n }) as Locator[\"describe\"];\n\n defineHiddenProperty(locator, LOCATOR_DESCRIBE_WRAPPED, true);\n }\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.locator.bind(page);\n page.locator = ((...args: Parameters<Page[\"locator\"]>) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as Page[\"locator\"];\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.newPage.bind(context);\n context.newPage = (async (...args: Parameters<BrowserContext[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as BrowserContext[\"newPage\"];\n\n const originalPages = context.pages?.bind(context);\n if (originalPages) {\n context.pages = (() =>\n originalPages().map((page) =>\n augmentPage(page),\n )) as BrowserContext[\"pages\"];\n }\n\n if (!(context as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(context, \"agent\", createAgentStub());\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.newContext.bind(browser);\n browser.newContext = (async (...args: Parameters<Browser[\"newContext\"]>) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as Browser[\"newContext\"];\n\n const originalNewPage = browser.newPage.bind(browser);\n browser.newPage = (async (...args: Parameters<Browser[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as Browser[\"newPage\"];\n\n const originalContexts = browser.contexts.bind(browser);\n browser.contexts = (() =>\n originalContexts().map((context) =>\n augmentBrowserContext(context),\n )) as Browser[\"contexts\"];\n\n if (!(browser as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(browser, \"agent\", createAgentStub());\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.launch.bind(browserType);\n browserType.launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser);\n }) as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = browserType.connect?.bind(browserType);\n if (originalConnect) {\n browserType.connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = browserType.connectOverCDP?.bind(browserType);\n if (originalConnectOverCDP) {\n browserType.connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext =\n browserType.launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n browserType.launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context);\n }) as NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n","import { isObject } from \"../type-predicate/is-object\";\nimport { requireApiKey } from \"../runtime\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_ENDPOINT = \"https://api.stably.ai/internal/v1/assert\";\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 { success, reason } = 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 success,\n reason,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { success, reason } = 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 { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n targetType,\n condition,\n didPass,\n isNot,\n reason,\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 ) {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n return {\n pass: verifyResult.pass,\n message: () =>\n createFailureMessage({\n targetType,\n condition,\n didPass: verifyResult.pass,\n reason: verifyResult.reason,\n isNot: this.isNot,\n }),\n };\n },\n} as const;\n"],"mappings":"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","names":["png","alias"]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/methods/agent.ts","../src/playwright-type-predicates.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/image-compare.ts","../src/screenshot.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/augment.ts","../src/ai/verify-prompt.ts","../src/expect.ts"],"sourcesContent":["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 type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type * as z4 from \"zod/v4/core\";\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport interface ExtractSchema extends z4.$ZodType {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n ): Promise<z4.util.SafeParseResult<z4.output<this>>>;\n}\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_ENDPOINT = \"https://api.stably.ai/internal/v2/extract\";\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\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: ReadonlyArray<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(\"Validation failed\", result.error.issues);\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 prompt,\n pageOrLocator,\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 schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\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 const pngBuffer = await pageOrLocator.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 method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\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 === false) {\n return raw.error;\n }\n\n const { value } = raw;\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\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 prompt,\n schema: options.schema,\n pageOrLocator,\n });\n }\n\n return extract({ prompt, pageOrLocator });\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","import type { Page } from \"@stablyai/internal-playwright-test\";\nimport { test } from \"@stablyai/internal-playwright-test\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentResponse } from \"./agent/tool-responses\";\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\n\ntype AgentOptions = {\n page: Page;\n maxCycles?: number;\n};\n\ntype AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\nconst AGENT_PATH = \"internal/v1/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\nexport function createAgentStub(): (\n prompt: string,\n options: AgentOptions,\n) => Promise<{ success: boolean }> {\n return async (prompt: string, options: AgentOptions) => {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n const browserContext = options.page.context();\n\n const tabManager = new Map<Page, string>();\n browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n message: prompt,\n isError: false,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n browserContext.on(\"page\", onNewPage);\n\n return await test.step(prompt, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: constructAgentPayload({\n sessionId,\n message: agentMessage.message,\n isError: agentMessage.isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\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 const agentResponse = responseJson as AgentResponse;\n\n agentMessage = await (async () => {\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { message: `pressed \"${text}\"` };\n }\n return { message: \"pressed key\" };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { message: `typed \"${text}\"` };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { message: `mouse moved to [${x}, ${y}]` };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { message: `left click at [${x}, ${y}]` };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { message: `right click at [${x}, ${y}]` };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { message: `double click at [${x}, ${y}]` };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { message: `triple click at [${x}, ${y}]` };\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 {\n message: `dragged from [${startX}, ${startY}] to [${endX}, ${endY}]`,\n };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { message: \"captured screenshot\" };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? 3000;\n await activePage.waitForTimeout(waitMs);\n return { message: `waited ${waitMs}ms` };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return { message: `navigated to \"${agentResponse.url}\"` };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n return { 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 message: `switched to \"${agentResponse.tab_alias}\"`,\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n 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 return { message: \"navigated back\" };\n }\n case \"terminate_test\": {\n const { success, reason } = agentResponse;\n finalSuccess = success;\n return { message: reason, shouldTerminate: true };\n }\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n return { message, isError: true };\n }\n })();\n }\n } finally {\n browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n };\n}\n","import { Page, Locator } from \"@stablyai/internal-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","/**\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","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\nimport * as jpeg from \"jpeg-js\";\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, width: png.width, height: png.height };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, width: img.width, height: img.height };\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, width: png.width, height: png.height };\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","import type { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\nimport { isPage } from \"./playwright-type-predicates\";\nimport { imagesAreSimilar } from \"./image-compare\";\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) break;\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 { Page } from \"@stablyai/internal-playwright-test\";\n\nexport function constructAgentPayload({\n sessionId,\n message,\n isError,\n screenshot,\n tabManager,\n activePage,\n additionalContext,\n}: {\n sessionId: string;\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 form.append(\"session_id\", sessionId);\n form.append(\"message\", message);\n if (isError) {\n form.append(\"is_error\", JSON.stringify(isError));\n }\n if (additionalContext) {\n form.append(\"additional_context\", JSON.stringify(additionalContext));\n }\n\n const viewportSize = activePage.viewportSize();\n if (viewportSize) {\n form.append(\"page_dimensions\", JSON.stringify(viewportSize));\n }\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 const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n form.append(\"all_pages\", JSON.stringify(tabs));\n\n const activePageAlias = tabManager.get(activePage);\n if (activePageAlias) {\n form.append(\"active_page_alias\", activePageAlias);\n }\n return form;\n}\n","import type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@stablyai/internal-playwright-test\";\n\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\nimport { createAgentStub } from \"./methods/agent\";\n\nexport interface LocatorDescribeOptions {\n autoHeal?: boolean;\n}\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst LOCATOR_DESCRIBE_WRAPPED = Symbol.for(\n \"stably.playwright.locatorDescribeWrapped\",\n);\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 value,\n enumerable: false,\n configurable: true,\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 const markerTarget = locator as unknown as Record<PropertyKey, unknown>;\n\n if (\n typeof locator.describe === \"function\" &&\n !markerTarget[LOCATOR_DESCRIBE_WRAPPED]\n ) {\n const originalDescribe = locator.describe.bind(locator);\n locator.describe = ((\n description: string,\n options?: LocatorDescribeOptions,\n ) => {\n const result = originalDescribe(description, options);\n return result ? augmentLocator(result as Locator) : result;\n }) as Locator[\"describe\"];\n\n defineHiddenProperty(locator, LOCATOR_DESCRIBE_WRAPPED, true);\n }\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.locator.bind(page);\n page.locator = ((...args: Parameters<Page[\"locator\"]>) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as Page[\"locator\"];\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.newPage.bind(context);\n context.newPage = (async (...args: Parameters<BrowserContext[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as BrowserContext[\"newPage\"];\n\n const originalPages = context.pages?.bind(context);\n if (originalPages) {\n context.pages = (() =>\n originalPages().map((page) =>\n augmentPage(page),\n )) as BrowserContext[\"pages\"];\n }\n\n if (!(context as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(context, \"agent\", createAgentStub());\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.newContext.bind(browser);\n browser.newContext = (async (...args: Parameters<Browser[\"newContext\"]>) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as Browser[\"newContext\"];\n\n const originalNewPage = browser.newPage.bind(browser);\n browser.newPage = (async (...args: Parameters<Browser[\"newPage\"]>) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as Browser[\"newPage\"];\n\n const originalContexts = browser.contexts.bind(browser);\n browser.contexts = (() =>\n originalContexts().map((context) =>\n augmentBrowserContext(context),\n )) as Browser[\"contexts\"];\n\n if (!(browser as unknown as { agent?: unknown }).agent) {\n defineHiddenProperty(browser, \"agent\", createAgentStub());\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.launch.bind(browserType);\n browserType.launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser);\n }) as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = browserType.connect?.bind(browserType);\n if (originalConnect) {\n browserType.connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = browserType.connectOverCDP?.bind(browserType);\n if (originalConnectOverCDP) {\n browserType.connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser);\n }) as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext =\n browserType.launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n browserType.launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context);\n }) as NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n","import { isObject } from \"../type-predicate/is-object\";\nimport { requireApiKey } from \"../runtime\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_ENDPOINT = \"https://api.stably.ai/internal/v1/assert\";\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 { success, reason } = 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 success,\n reason,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n method: \"POST\",\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n body: form,\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { success, reason } = 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 { Locator, Page } from \"@stablyai/internal-playwright-test\";\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n targetType,\n condition,\n didPass,\n isNot,\n reason,\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 ) {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n return {\n pass: verifyResult.pass,\n message: () =>\n createFailureMessage({\n targetType,\n condition,\n didPass: verifyResult.pass,\n reason: verifyResult.reason,\n isNot: this.isNot,\n }),\n };\n },\n} as const;\n"],"mappings":"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","names":["png","alias"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stablyai/playwright-base",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Shared augmentation runtime for Stably Playwright wrappers",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"node": ">=18"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@stablyai/internal-playwright-test": "0.1.
|
|
21
|
+
"@stablyai/internal-playwright-test": "0.1.17",
|
|
22
22
|
"jpeg-js": "^0.4.4",
|
|
23
23
|
"pixelmatch": "^7.1.0",
|
|
24
24
|
"pngjs": "^7.0.0"
|