@stablyai/playwright-base 1.0.1 → 2.0.0-next.2
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 +28 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.mjs +28 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -71,7 +71,7 @@ var isObject = (value) => {
|
|
|
71
71
|
// src/ai/metadata.ts
|
|
72
72
|
var SDK_METADATA_HEADERS = {
|
|
73
73
|
"X-Client-Name": "stably-playwright-sdk-js",
|
|
74
|
-
"X-Client-Version": "
|
|
74
|
+
"X-Client-Version": "2.0.0-next.2"
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
// src/ai/verify-prompt.ts
|
|
@@ -650,6 +650,7 @@ ${ariaSnapshot}` }
|
|
|
650
650
|
const { reason, success } = agentResponse;
|
|
651
651
|
return {
|
|
652
652
|
activePage,
|
|
653
|
+
failureReason: success ? void 0 : reason,
|
|
653
654
|
finalSuccess: success,
|
|
654
655
|
result: { message: reason, shouldTerminate: true }
|
|
655
656
|
};
|
|
@@ -678,7 +679,8 @@ var Agent = class {
|
|
|
678
679
|
*
|
|
679
680
|
* @param prompt - Natural language instruction describing what the agent should do
|
|
680
681
|
* @param options - Configuration for the agent's behavior including the page to operate on
|
|
681
|
-
* @returns Promise that resolves
|
|
682
|
+
* @returns Promise that resolves when the agent successfully completes the task
|
|
683
|
+
* @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
|
|
682
684
|
*
|
|
683
685
|
* @example
|
|
684
686
|
* ```typescript
|
|
@@ -689,14 +691,18 @@ var Agent = class {
|
|
|
689
691
|
* await agent.act('Navigate to settings, enable notifications, and save changes', { page });
|
|
690
692
|
*
|
|
691
693
|
* // With custom options
|
|
692
|
-
*
|
|
694
|
+
* await agent.act('Complete the checkout process', {
|
|
693
695
|
* page,
|
|
694
696
|
* maxCycles: 20,
|
|
695
697
|
* model: 'gpt-4'
|
|
696
698
|
* });
|
|
697
699
|
*
|
|
698
|
-
*
|
|
700
|
+
* // Handling failures with try-catch
|
|
701
|
+
* try {
|
|
702
|
+
* await agent.act('Complete the task', { page });
|
|
699
703
|
* console.log('Agent completed the task successfully');
|
|
704
|
+
* } catch (error) {
|
|
705
|
+
* console.error('Agent failed:', error.message);
|
|
700
706
|
* }
|
|
701
707
|
* ```
|
|
702
708
|
*/
|
|
@@ -714,6 +720,7 @@ var Agent = class {
|
|
|
714
720
|
shouldTerminate: false
|
|
715
721
|
};
|
|
716
722
|
let finalSuccess;
|
|
723
|
+
let failureReason;
|
|
717
724
|
let newPageOpenedMsg;
|
|
718
725
|
const sessionId = crypto.randomUUID();
|
|
719
726
|
const onNewPage = async (page) => {
|
|
@@ -760,16 +767,18 @@ var Agent = class {
|
|
|
760
767
|
`Agent call failed: ${JSON.stringify(responseJson)}`
|
|
761
768
|
);
|
|
762
769
|
}
|
|
763
|
-
const reasoningTexts = responseJson.map((r) => r.content).filter((content) => content !== void 0);
|
|
770
|
+
const reasoningTexts = responseJson.map((r) => r.content?.trim()).filter((content) => content !== void 0);
|
|
764
771
|
const reasoningText = reasoningTexts.join("\n\n");
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
772
|
+
if (reasoningText) {
|
|
773
|
+
const truncatedReasoningText = truncate(reasoningText, 120);
|
|
774
|
+
await stepInfo.attach(
|
|
775
|
+
`[Thinking ${i + 1}] ${truncatedReasoningText}`,
|
|
776
|
+
{
|
|
777
|
+
body: reasoningText,
|
|
778
|
+
contentType: "text/plain"
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
}
|
|
773
782
|
return responseJson;
|
|
774
783
|
});
|
|
775
784
|
let combinedMessages = [];
|
|
@@ -778,6 +787,7 @@ var Agent = class {
|
|
|
778
787
|
for (const agentResponse of agentResponses) {
|
|
779
788
|
const {
|
|
780
789
|
activePage: newActivePage,
|
|
790
|
+
failureReason: maybeFailureReason,
|
|
781
791
|
finalSuccess: maybeFinal,
|
|
782
792
|
result
|
|
783
793
|
} = await execResponse({
|
|
@@ -789,6 +799,7 @@ var Agent = class {
|
|
|
789
799
|
activePage = newActivePage;
|
|
790
800
|
combinedMessages.push(result.message);
|
|
791
801
|
finalSuccess = maybeFinal ?? finalSuccess;
|
|
802
|
+
failureReason = maybeFailureReason ?? failureReason;
|
|
792
803
|
if (result.isError) {
|
|
793
804
|
aggregatedIsError = true;
|
|
794
805
|
}
|
|
@@ -806,7 +817,10 @@ var Agent = class {
|
|
|
806
817
|
} finally {
|
|
807
818
|
this.browserContext.off("page", onNewPage);
|
|
808
819
|
}
|
|
809
|
-
|
|
820
|
+
const success = finalSuccess ?? false;
|
|
821
|
+
if (!success) {
|
|
822
|
+
throw new Error(failureReason ?? "Agent failed to complete the task");
|
|
823
|
+
}
|
|
810
824
|
});
|
|
811
825
|
}
|
|
812
826
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Page as InternalPage } from \"@playwright/test\";\n\nimport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\n\nimport { stablyPlaywrightMatchers } from \"./expect\";\nimport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n} from \"./playwright-augment/augment\";\nimport { requireApiKey } from \"./runtime\";\n\nexport { setApiKey } from \"./runtime\";\nexport { Agent } from \"./playwright-augment/methods/agent\";\n\nexport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\nexport type ScreenshotPromptOptions =\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n import(\"@playwright/test\").PageAssertionsToHaveScreenshotOptions;\nexport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n stablyPlaywrightMatchers,\n requireApiKey,\n};\n\n// eslint-disable-next-line unused-imports/no-unused-vars\nexport type Expect<T = InternalPage> = {\n toMatchScreenshotPrompt(\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<void>;\n};\n\ndeclare module \"@playwright/test\" {\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Locator {\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Page {\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface BrowserContext {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within this browser context and can interact with all pages in the context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const context = await browser.newContext();\n * const page = await context.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent for this context\n * const agent = context.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Click the login button and enter credentials', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Browser {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within a browser context and can interact with all pages in that context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const browser = await chromium.launch();\n * const page = await browser.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent\n * const agent = browser.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Fill out the registration form and submit', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n}\n","import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v1/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves with the result of the agent's actions\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * const result = await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * if (result.success) {\n * console.log('Agent completed the task successfully');\n * }\n * ```\n */\n async act(\n prompt: string,\n options: AgentActOptions,\n ): Promise<{ success: boolean }> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`,\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content)\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n },\n );\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":"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","names":["png","import_test","STABLY_API_URL","alias","import_test","STABLY_API_URL"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Page as InternalPage } from \"@playwright/test\";\n\nimport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\n\nimport { stablyPlaywrightMatchers } from \"./expect\";\nimport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n} from \"./playwright-augment/augment\";\nimport { requireApiKey } from \"./runtime\";\n\nexport { setApiKey } from \"./runtime\";\nexport { Agent } from \"./playwright-augment/methods/agent\";\n\nexport type { ExtractSchema, SchemaOutput } from \"./ai/extract\";\nexport type ScreenshotPromptOptions =\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n import(\"@playwright/test\").PageAssertionsToHaveScreenshotOptions;\nexport {\n augmentBrowser,\n augmentBrowserContext,\n augmentBrowserType,\n augmentLocator,\n augmentPage,\n stablyPlaywrightMatchers,\n requireApiKey,\n};\n\n// eslint-disable-next-line unused-imports/no-unused-vars\nexport type Expect<T = InternalPage> = {\n toMatchScreenshotPrompt(\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<void>;\n};\n\ndeclare module \"@playwright/test\" {\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Locator {\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this locator using Stably AI.\n *\n * Takes a screenshot of the locator and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Page {\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. When a schema is provided, the extracted data is validated and\n * typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @returns A string containing the extracted information\n */\n extract(prompt: string): Promise<string>;\n /**\n * Extracts information from this page using Stably AI.\n *\n * Takes a screenshot of the page and uses AI to extract information based on the\n * provided prompt. The extracted data is validated and typed according to the schema.\n *\n * @param prompt - A natural language description of what information to extract\n * @param options - Configuration object containing the Zod schema for validation\n * @param options.schema - Zod schema to validate and type the extracted data\n * @returns Typed data matching the provided schema\n */\n extract<T extends ExtractSchema>(\n prompt: string,\n options: { schema: T },\n ): Promise<SchemaOutput<T>>;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface BrowserContext {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within this browser context and can interact with all pages in the context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const context = await browser.newContext();\n * const page = await context.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent for this context\n * const agent = context.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Click the login button and enter credentials', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions\n interface Browser {\n /**\n * Creates a new AI agent instance for automating browser interactions.\n *\n * An agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page, makes autonomous decisions, and executes actions like clicking,\n * typing, navigating, and verifying page state.\n *\n * The agent operates within a browser context and can interact with all pages in that context.\n * Use the returned agent's [agent.act(prompt, options)](#agent-act) method to give instructions.\n * The page to operate on is specified when calling `act()`.\n *\n * **Usage**\n *\n * ```js\n * const browser = await chromium.launch();\n * const page = await browser.newPage();\n * await page.goto('https://example.com');\n *\n * // Create an agent\n * const agent = browser.newAgent();\n *\n * // Give the agent natural language instructions with the page to operate on\n * await agent.act('Fill out the registration form and submit', { page });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n newAgent(): import(\"./playwright-augment/methods/agent\").Agent;\n }\n}\n","import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v1/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves when the agent successfully completes the task\n * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * // Handling failures with try-catch\n * try {\n * await agent.act('Complete the task', { page });\n * console.log('Agent completed the task successfully');\n * } catch (error) {\n * console.error('Agent failed:', error.message);\n * }\n * ```\n */\n async act(prompt: string, options: AgentActOptions): Promise<void> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let failureReason: string | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content?.trim())\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n // Only attach if there's actual reasoning content\n if (reasoningText) {\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n }\n );\n }\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n failureReason: maybeFailureReason,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n failureReason = maybeFailureReason ?? failureReason;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n const success = finalSuccess ?? false;\n if (!success) {\n throw new Error(failureReason ?? \"Agent failed to complete the task\");\n }\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n failureReason?: string;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n failureReason: success ? undefined : reason,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":"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","names":["png","import_test","STABLY_API_URL","alias","import_test","STABLY_API_URL"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -52,7 +52,8 @@ declare class Agent {
|
|
|
52
52
|
*
|
|
53
53
|
* @param prompt - Natural language instruction describing what the agent should do
|
|
54
54
|
* @param options - Configuration for the agent's behavior including the page to operate on
|
|
55
|
-
* @returns Promise that resolves
|
|
55
|
+
* @returns Promise that resolves when the agent successfully completes the task
|
|
56
|
+
* @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
|
|
56
57
|
*
|
|
57
58
|
* @example
|
|
58
59
|
* ```typescript
|
|
@@ -63,20 +64,22 @@ declare class Agent {
|
|
|
63
64
|
* await agent.act('Navigate to settings, enable notifications, and save changes', { page });
|
|
64
65
|
*
|
|
65
66
|
* // With custom options
|
|
66
|
-
*
|
|
67
|
+
* await agent.act('Complete the checkout process', {
|
|
67
68
|
* page,
|
|
68
69
|
* maxCycles: 20,
|
|
69
70
|
* model: 'gpt-4'
|
|
70
71
|
* });
|
|
71
72
|
*
|
|
72
|
-
*
|
|
73
|
+
* // Handling failures with try-catch
|
|
74
|
+
* try {
|
|
75
|
+
* await agent.act('Complete the task', { page });
|
|
73
76
|
* console.log('Agent completed the task successfully');
|
|
77
|
+
* } catch (error) {
|
|
78
|
+
* console.error('Agent failed:', error.message);
|
|
74
79
|
* }
|
|
75
80
|
* ```
|
|
76
81
|
*/
|
|
77
|
-
act(prompt: string, options: AgentActOptions): Promise<
|
|
78
|
-
success: boolean;
|
|
79
|
-
}>;
|
|
82
|
+
act(prompt: string, options: AgentActOptions): Promise<void>;
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
type ExtractSchema = {
|
package/dist/index.d.ts
CHANGED
|
@@ -52,7 +52,8 @@ declare class Agent {
|
|
|
52
52
|
*
|
|
53
53
|
* @param prompt - Natural language instruction describing what the agent should do
|
|
54
54
|
* @param options - Configuration for the agent's behavior including the page to operate on
|
|
55
|
-
* @returns Promise that resolves
|
|
55
|
+
* @returns Promise that resolves when the agent successfully completes the task
|
|
56
|
+
* @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
|
|
56
57
|
*
|
|
57
58
|
* @example
|
|
58
59
|
* ```typescript
|
|
@@ -63,20 +64,22 @@ declare class Agent {
|
|
|
63
64
|
* await agent.act('Navigate to settings, enable notifications, and save changes', { page });
|
|
64
65
|
*
|
|
65
66
|
* // With custom options
|
|
66
|
-
*
|
|
67
|
+
* await agent.act('Complete the checkout process', {
|
|
67
68
|
* page,
|
|
68
69
|
* maxCycles: 20,
|
|
69
70
|
* model: 'gpt-4'
|
|
70
71
|
* });
|
|
71
72
|
*
|
|
72
|
-
*
|
|
73
|
+
* // Handling failures with try-catch
|
|
74
|
+
* try {
|
|
75
|
+
* await agent.act('Complete the task', { page });
|
|
73
76
|
* console.log('Agent completed the task successfully');
|
|
77
|
+
* } catch (error) {
|
|
78
|
+
* console.error('Agent failed:', error.message);
|
|
74
79
|
* }
|
|
75
80
|
* ```
|
|
76
81
|
*/
|
|
77
|
-
act(prompt: string, options: AgentActOptions): Promise<
|
|
78
|
-
success: boolean;
|
|
79
|
-
}>;
|
|
82
|
+
act(prompt: string, options: AgentActOptions): Promise<void>;
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
type ExtractSchema = {
|
package/dist/index.mjs
CHANGED
|
@@ -34,7 +34,7 @@ var isObject = (value) => {
|
|
|
34
34
|
// src/ai/metadata.ts
|
|
35
35
|
var SDK_METADATA_HEADERS = {
|
|
36
36
|
"X-Client-Name": "stably-playwright-sdk-js",
|
|
37
|
-
"X-Client-Version": "
|
|
37
|
+
"X-Client-Version": "2.0.0-next.2"
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
// src/ai/verify-prompt.ts
|
|
@@ -613,6 +613,7 @@ ${ariaSnapshot}` }
|
|
|
613
613
|
const { reason, success } = agentResponse;
|
|
614
614
|
return {
|
|
615
615
|
activePage,
|
|
616
|
+
failureReason: success ? void 0 : reason,
|
|
616
617
|
finalSuccess: success,
|
|
617
618
|
result: { message: reason, shouldTerminate: true }
|
|
618
619
|
};
|
|
@@ -641,7 +642,8 @@ var Agent = class {
|
|
|
641
642
|
*
|
|
642
643
|
* @param prompt - Natural language instruction describing what the agent should do
|
|
643
644
|
* @param options - Configuration for the agent's behavior including the page to operate on
|
|
644
|
-
* @returns Promise that resolves
|
|
645
|
+
* @returns Promise that resolves when the agent successfully completes the task
|
|
646
|
+
* @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.
|
|
645
647
|
*
|
|
646
648
|
* @example
|
|
647
649
|
* ```typescript
|
|
@@ -652,14 +654,18 @@ var Agent = class {
|
|
|
652
654
|
* await agent.act('Navigate to settings, enable notifications, and save changes', { page });
|
|
653
655
|
*
|
|
654
656
|
* // With custom options
|
|
655
|
-
*
|
|
657
|
+
* await agent.act('Complete the checkout process', {
|
|
656
658
|
* page,
|
|
657
659
|
* maxCycles: 20,
|
|
658
660
|
* model: 'gpt-4'
|
|
659
661
|
* });
|
|
660
662
|
*
|
|
661
|
-
*
|
|
663
|
+
* // Handling failures with try-catch
|
|
664
|
+
* try {
|
|
665
|
+
* await agent.act('Complete the task', { page });
|
|
662
666
|
* console.log('Agent completed the task successfully');
|
|
667
|
+
* } catch (error) {
|
|
668
|
+
* console.error('Agent failed:', error.message);
|
|
663
669
|
* }
|
|
664
670
|
* ```
|
|
665
671
|
*/
|
|
@@ -677,6 +683,7 @@ var Agent = class {
|
|
|
677
683
|
shouldTerminate: false
|
|
678
684
|
};
|
|
679
685
|
let finalSuccess;
|
|
686
|
+
let failureReason;
|
|
680
687
|
let newPageOpenedMsg;
|
|
681
688
|
const sessionId = crypto.randomUUID();
|
|
682
689
|
const onNewPage = async (page) => {
|
|
@@ -723,16 +730,18 @@ var Agent = class {
|
|
|
723
730
|
`Agent call failed: ${JSON.stringify(responseJson)}`
|
|
724
731
|
);
|
|
725
732
|
}
|
|
726
|
-
const reasoningTexts = responseJson.map((r) => r.content).filter((content) => content !== void 0);
|
|
733
|
+
const reasoningTexts = responseJson.map((r) => r.content?.trim()).filter((content) => content !== void 0);
|
|
727
734
|
const reasoningText = reasoningTexts.join("\n\n");
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
735
|
+
if (reasoningText) {
|
|
736
|
+
const truncatedReasoningText = truncate(reasoningText, 120);
|
|
737
|
+
await stepInfo.attach(
|
|
738
|
+
`[Thinking ${i + 1}] ${truncatedReasoningText}`,
|
|
739
|
+
{
|
|
740
|
+
body: reasoningText,
|
|
741
|
+
contentType: "text/plain"
|
|
742
|
+
}
|
|
743
|
+
);
|
|
744
|
+
}
|
|
736
745
|
return responseJson;
|
|
737
746
|
});
|
|
738
747
|
let combinedMessages = [];
|
|
@@ -741,6 +750,7 @@ var Agent = class {
|
|
|
741
750
|
for (const agentResponse of agentResponses) {
|
|
742
751
|
const {
|
|
743
752
|
activePage: newActivePage,
|
|
753
|
+
failureReason: maybeFailureReason,
|
|
744
754
|
finalSuccess: maybeFinal,
|
|
745
755
|
result
|
|
746
756
|
} = await execResponse({
|
|
@@ -752,6 +762,7 @@ var Agent = class {
|
|
|
752
762
|
activePage = newActivePage;
|
|
753
763
|
combinedMessages.push(result.message);
|
|
754
764
|
finalSuccess = maybeFinal ?? finalSuccess;
|
|
765
|
+
failureReason = maybeFailureReason ?? failureReason;
|
|
755
766
|
if (result.isError) {
|
|
756
767
|
aggregatedIsError = true;
|
|
757
768
|
}
|
|
@@ -769,7 +780,10 @@ var Agent = class {
|
|
|
769
780
|
} finally {
|
|
770
781
|
this.browserContext.off("page", onNewPage);
|
|
771
782
|
}
|
|
772
|
-
|
|
783
|
+
const success = finalSuccess ?? false;
|
|
784
|
+
if (!success) {
|
|
785
|
+
throw new Error(failureReason ?? "Agent failed to complete the task");
|
|
786
|
+
}
|
|
773
787
|
});
|
|
774
788
|
}
|
|
775
789
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v1/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves with the result of the agent's actions\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * const result = await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * if (result.success) {\n * console.log('Agent completed the task successfully');\n * }\n * ```\n */\n async act(\n prompt: string,\n options: AgentActOptions,\n ): Promise<{ success: boolean }> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`,\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content)\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n },\n );\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n return { success: finalSuccess ?? false };\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":"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","names":["png","test","STABLY_API_URL","alias","test","test","STABLY_API_URL","test"]}
|
|
1
|
+
{"version":3,"sources":["../src/expect.ts","../src/runtime.ts","../src/type-predicate/is-object.ts","../src/ai/metadata.ts","../src/ai/verify-prompt.ts","../src/playwright-type-predicates.ts","../src/image-compare.ts","../../../node_modules/.pnpm/pixelmatch@7.1.0/node_modules/pixelmatch/index.js","../src/screenshot.ts","../src/playwright-augment/methods/agent.ts","../src/utils/truncate.ts","../src/playwright-augment/methods/agent/construct-payload.ts","../src/playwright-augment/methods/agent/exec-response.ts","../src/ai/extract.ts","../src/playwright-augment/methods/extract.ts","../src/playwright-augment/augment.ts"],"sourcesContent":["import type { Locator, MatcherReturnType, Page } from \"@playwright/test\";\nimport { test } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { verifyPrompt } from \"./ai/verify-prompt\";\nimport { isLocator, isPage } from \"./playwright-type-predicates\";\nimport { takeStableScreenshot } from \"./screenshot\";\n\ntype VerifyTargetType = \"page\" | \"locator\";\n\ntype MatcherContext = {\n isNot: boolean;\n message?: () => string;\n};\n\nfunction createFailureMessage({\n condition,\n didPass,\n isNot,\n reason,\n targetType,\n}: {\n targetType: VerifyTargetType;\n condition: string;\n didPass: boolean;\n isNot: boolean;\n reason?: string;\n}): string {\n const expectation = isNot ? \"not to satisfy\" : \"to satisfy\";\n const result = didPass ? \"it did\" : \"it did not\";\n\n let message = `Expected ${targetType} ${expectation} ${JSON.stringify(condition)}, but ${result}.`;\n if (reason) {\n message += `\\n\\nReason: ${reason}`;\n }\n\n return message;\n}\n\nexport const stablyPlaywrightMatchers = {\n async toMatchScreenshotPrompt(\n this: MatcherContext,\n received: Page | Locator,\n condition: string,\n options?: ScreenshotPromptOptions,\n ): Promise<MatcherReturnType> {\n const target = isPage(received)\n ? received\n : isLocator(received)\n ? received\n : undefined;\n if (!target) {\n // Should never happen\n throw new Error(\n \"toMatchScreenshotPrompt only supports Playwright Page and Locator instances.\",\n );\n }\n const targetType: VerifyTargetType = isPage(target) ? \"page\" : \"locator\";\n\n // Wait for two consecutive identical screenshots before sending to AI\n const screenshot = await takeStableScreenshot(target, options);\n\n const verifyResult = await verifyPrompt({ prompt: condition, screenshot });\n\n const testInfo = test.info();\n testInfo.attachments.push({\n body: Buffer.from(\n JSON.stringify(\n {\n pass: verifyResult.pass,\n prompt: condition,\n reasoning: verifyResult.reason,\n },\n null,\n 2,\n ),\n \"utf-8\",\n ),\n contentType: \"application/json\",\n name: \"toMatchScreenshotPrompt-reasoning\",\n });\n\n return {\n message: () =>\n createFailureMessage({\n condition,\n didPass: verifyResult.pass,\n isNot: this.isNot,\n reason: verifyResult.reason,\n targetType,\n }),\n name: \"toMatchScreenshotPrompt\",\n pass: verifyResult.pass,\n };\n },\n} as const;\n","let configuredApiKey: string | undefined = process.env.STABLY_API_KEY;\n\nexport function setApiKey(apiKey: string): void {\n configuredApiKey = apiKey;\n}\n\nexport function getApiKey(): string | undefined {\n return configuredApiKey;\n}\n\nexport function requireApiKey(): string {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error(\n \"Missing Stably API key. Call setApiKey(apiKey) or set the STABLY_API_KEY environment variable.\",\n );\n }\n return apiKey;\n}\n","export const isObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null;\n};\n","declare const __PACKAGE_VERSION__: string;\n\nexport const SDK_METADATA_HEADERS = {\n \"X-Client-Name\": \"stably-playwright-sdk-js\",\n \"X-Client-Version\": __PACKAGE_VERSION__,\n};\n","import { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\nconst PROMPT_ASSERTION_PATH = \"internal/v1/assert\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst PROMPT_ASSERTION_ENDPOINT = new URL(\n PROMPT_ASSERTION_PATH,\n STABLY_API_URL,\n).toString();\n\ntype ParsedSuccessResponse = { success: boolean; reason?: string };\n\nconst parseSuccessResponse = (value: unknown): ParsedSuccessResponse => {\n if (!isObject(value)) {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n const { reason, success } = value;\n if (typeof success !== \"boolean\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n if (reason !== undefined && typeof reason !== \"string\") {\n throw new Error(\"Verify prompt returned unexpected response shape\");\n }\n\n return {\n reason,\n success,\n };\n};\n\ntype ParsedErrorResponse = { error: string };\n\nconst parseErrorResponse = (\n value: unknown,\n): ParsedErrorResponse | undefined => {\n if (!isObject(value)) {\n return undefined;\n }\n\n const { error } = value;\n return typeof error !== \"string\" ? undefined : { error };\n};\n\nexport async function verifyPrompt({\n prompt,\n screenshot,\n}: {\n prompt: string;\n screenshot: Uint8Array;\n}): Promise<{\n pass: boolean;\n reason?: string;\n}> {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n const u8 = Uint8Array.from(screenshot);\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(PROMPT_ASSERTION_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const parsed = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n const { reason, success } = parseSuccessResponse(parsed);\n return {\n pass: success,\n reason,\n };\n }\n\n const err = parseErrorResponse(parsed);\n throw new Error(\n `Verify prompt failed (${response.status})${err ? `: ${err.error}` : \"\"}`,\n );\n}\n","import type { Page, Locator } from \"@playwright/test\";\n\nexport function isPage(candidate: unknown): candidate is Page {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Page).screenshot === \"function\" &&\n typeof (candidate as Page).goto === \"function\"\n );\n}\n\nexport function isLocator(candidate: unknown): candidate is Locator {\n return (\n typeof candidate === \"object\" &&\n candidate !== null &&\n typeof (candidate as Locator).screenshot === \"function\" &&\n typeof (candidate as Locator).nth === \"function\"\n );\n}\n","// Note: pixelmatch seems to be pure ESM so mark it as noExternal in tsup config\nimport * as jpeg from \"jpeg-js\";\nimport pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\n\nconst isPng = (buffer: Buffer): boolean => {\n return (\n buffer.length >= 8 &&\n buffer[0] === 0x89 &&\n buffer[1] === 0x50 &&\n buffer[2] === 0x4e &&\n buffer[3] === 0x47 &&\n buffer[4] === 0x0d &&\n buffer[5] === 0x0a &&\n buffer[6] === 0x1a &&\n buffer[7] === 0x0a\n );\n};\n\nconst isJpeg = (buffer: Buffer): boolean => {\n return buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8;\n};\n\nconst decodeImage = (\n buffer: Buffer,\n): { data: Uint8Array; width: number; height: number } => {\n if (isPng(buffer)) {\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n }\n if (isJpeg(buffer)) {\n const img = jpeg.decode(buffer, { maxMemoryUsageInMB: 1024 });\n return { data: img.data, height: img.height, width: img.width };\n }\n // Default to PNG decode; if it fails upstream, treat as different sizes\n const png = PNG.sync.read(buffer);\n return { data: png.data, height: png.height, width: png.width };\n};\n\nexport const imagesAreSimilar = ({\n image1,\n image2,\n threshold,\n}: {\n image1: Buffer;\n image2: Buffer;\n threshold: number;\n}): boolean => {\n const decodedImage1 = decodeImage(image1);\n const decodedImage2 = decodeImage(image2);\n if (\n decodedImage1.width !== decodedImage2.width ||\n decodedImage1.height !== decodedImage2.height\n ) {\n return false;\n }\n const diffRgbaData = new Uint8Array(\n decodedImage1.width * decodedImage1.height * 4,\n );\n const numDiffPixels = pixelmatch(\n decodedImage1.data,\n decodedImage2.data,\n diffRgbaData,\n decodedImage1.width,\n decodedImage1.height,\n { threshold },\n );\n\n return numDiffPixels === 0;\n};\n","/**\n * Compare two equally sized images, pixel by pixel.\n *\n * @param {Uint8Array | Uint8ClampedArray} img1 First image data.\n * @param {Uint8Array | Uint8ClampedArray} img2 Second image data.\n * @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.\n * @param {number} width Input images width.\n * @param {number} height Input images height.\n *\n * @param {Object} [options]\n * @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.\n * @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.\n * @param {number} [options.alpha=0.1] Opacity of original image in diff output.\n * @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.\n * @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.\n * @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.\n * @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).\n *\n * @return {number} The number of mismatched pixels.\n */\nexport default function pixelmatch(img1, img2, output, width, height, options = {}) {\n const {\n threshold = 0.1,\n alpha = 0.1,\n aaColor = [255, 255, 0],\n diffColor = [255, 0, 0],\n includeAA, diffColorAlt, diffMask\n } = options;\n\n if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))\n throw new Error('Image data: Uint8Array, Uint8ClampedArray or Buffer expected.');\n\n if (img1.length !== img2.length || (output && output.length !== img1.length))\n throw new Error('Image sizes do not match.');\n\n if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.');\n\n // check if images are identical\n const len = width * height;\n const a32 = new Uint32Array(img1.buffer, img1.byteOffset, len);\n const b32 = new Uint32Array(img2.buffer, img2.byteOffset, len);\n let identical = true;\n\n for (let i = 0; i < len; i++) {\n if (a32[i] !== b32[i]) { identical = false; break; }\n }\n if (identical) { // fast path if identical\n if (output && !diffMask) {\n for (let i = 0; i < len; i++) drawGrayPixel(img1, 4 * i, alpha, output);\n }\n return 0;\n }\n\n // maximum acceptable square distance between two colors;\n // 35215 is the maximum possible value for the YIQ difference metric\n const maxDelta = 35215 * threshold * threshold;\n const [aaR, aaG, aaB] = aaColor;\n const [diffR, diffG, diffB] = diffColor;\n const [altR, altG, altB] = diffColorAlt || diffColor;\n let diff = 0;\n\n // compare each pixel of one image against the other one\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n\n const i = y * width + x;\n const pos = i * 4;\n\n // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker\n const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);\n\n // the color difference is above the threshold\n if (Math.abs(delta) > maxDelta) {\n // check it's a real rendering difference or just anti-aliasing\n const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, b32, a32);\n if (!includeAA && isAA) {\n // one of the pixels is anti-aliasing; draw as yellow and do not count as difference\n // note that we do not include such pixels in a mask\n if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);\n\n } else {\n // found substantial difference not caused by anti-aliasing; draw it as such\n if (output) {\n if (delta < 0) {\n drawPixel(output, pos, altR, altG, altB);\n } else {\n drawPixel(output, pos, diffR, diffG, diffB);\n }\n }\n diff++;\n }\n\n } else if (output && !diffMask) {\n // pixels are similar; draw background as grayscale image blended with white\n drawGrayPixel(img1, pos, alpha, output);\n }\n }\n }\n\n // return the number of different pixels\n return diff;\n}\n\n/** @param {Uint8Array | Uint8ClampedArray} arr */\nfunction isPixelData(arr) {\n // work around instanceof Uint8Array not working properly in some Jest environments\n return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;\n}\n\n/**\n * Check if a pixel is likely a part of anti-aliasing;\n * based on \"Anti-aliased Pixel and Intensity Slope Detector\" paper by V. Vysniauskas, 2009\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n * @param {Uint32Array} a32\n * @param {Uint32Array} b32\n */\nfunction antialiased(img, x1, y1, width, height, a32, b32) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const pos = y1 * width + x1;\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n let min = 0;\n let max = 0;\n let minX = 0;\n let minY = 0;\n let maxX = 0;\n let maxY = 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n\n // brightness delta between the center pixel and adjacent one\n const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);\n\n // count the number of equal, darker and brighter adjacent pixels\n if (delta === 0) {\n zeroes++;\n // if found more than 2 equal siblings, it's definitely not anti-aliasing\n if (zeroes > 2) return false;\n\n // remember the darkest pixel\n } else if (delta < min) {\n min = delta;\n minX = x;\n minY = y;\n\n // remember the brightest pixel\n } else if (delta > max) {\n max = delta;\n maxX = x;\n maxY = y;\n }\n }\n }\n\n // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing\n if (min === 0 || max === 0) return false;\n\n // if either the darkest or the brightest pixel has 3+ equal siblings in both images\n // (definitely not anti-aliased), this pixel is anti-aliased\n return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||\n (hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));\n}\n\n/**\n * Check if a pixel has 3+ adjacent pixels of the same color.\n * @param {Uint32Array} img\n * @param {number} x1\n * @param {number} y1\n * @param {number} width\n * @param {number} height\n */\nfunction hasManySiblings(img, x1, y1, width, height) {\n const x0 = Math.max(x1 - 1, 0);\n const y0 = Math.max(y1 - 1, 0);\n const x2 = Math.min(x1 + 1, width - 1);\n const y2 = Math.min(y1 + 1, height - 1);\n const val = img[y1 * width + x1];\n let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;\n\n // go through 8 adjacent pixels\n for (let x = x0; x <= x2; x++) {\n for (let y = y0; y <= y2; y++) {\n if (x === x1 && y === y1) continue;\n zeroes += +(val === img[y * width + x]);\n if (zeroes > 2) return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate color difference according to the paper \"Measuring perceived color difference\n * using YIQ NTSC transmission color space in mobile applications\" by Y. Kotsarenko and F. Ramos\n * @param {Uint8Array | Uint8ClampedArray} img1\n * @param {Uint8Array | Uint8ClampedArray} img2\n * @param {number} k\n * @param {number} m\n * @param {boolean} yOnly\n */\nfunction colorDelta(img1, img2, k, m, yOnly) {\n const r1 = img1[k];\n const g1 = img1[k + 1];\n const b1 = img1[k + 2];\n const a1 = img1[k + 3];\n const r2 = img2[m];\n const g2 = img2[m + 1];\n const b2 = img2[m + 2];\n const a2 = img2[m + 3];\n\n let dr = r1 - r2;\n let dg = g1 - g2;\n let db = b1 - b2;\n const da = a1 - a2;\n\n if (!dr && !dg && !db && !da) return 0;\n\n if (a1 < 255 || a2 < 255) { // blend pixels with background\n const rb = 48 + 159 * (k % 2);\n const gb = 48 + 159 * ((k / 1.618033988749895 | 0) % 2);\n const bb = 48 + 159 * ((k / 2.618033988749895 | 0) % 2);\n dr = (r1 * a1 - r2 * a2 - rb * da) / 255;\n dg = (g1 * a1 - g2 * a2 - gb * da) / 255;\n db = (b1 * a1 - b2 * a2 - bb * da) / 255;\n }\n\n const y = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;\n\n if (yOnly) return y; // brightness difference only\n\n const i = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;\n const q = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;\n\n const delta = 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q;\n\n // encode whether the pixel lightens or darkens in the sign\n return y > 0 ? -delta : delta;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} output\n * @param {number} pos\n * @param {number} r\n * @param {number} g\n * @param {number} b\n */\nfunction drawPixel(output, pos, r, g, b) {\n output[pos + 0] = r;\n output[pos + 1] = g;\n output[pos + 2] = b;\n output[pos + 3] = 255;\n}\n\n/**\n * @param {Uint8Array | Uint8ClampedArray} img\n * @param {number} i\n * @param {number} alpha\n * @param {Uint8Array | Uint8ClampedArray} output\n */\nfunction drawGrayPixel(img, i, alpha, output) {\n const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;\n drawPixel(output, i, val, val, val);\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport type { ScreenshotPromptOptions } from \"./index\";\n\nimport { imagesAreSimilar } from \"./image-compare\";\nimport { isPage } from \"./playwright-type-predicates\";\n\nexport async function takeStableScreenshot(\n target: Page | Locator,\n options?: ScreenshotPromptOptions,\n): Promise<Buffer> {\n const page = isPage(target) ? target : target.page();\n\n // Use a small budget for stabilization within the overall assertion timeout.\n // We allocate up to 25% of the total timeout (bounded between 300ms and 2000ms).\n const totalTimeout =\n (options as { timeout?: number } | undefined)?.timeout ?? 5000;\n // Budget is 25% of the total timeout\n const stabilizationBudgetMs = Math.floor(totalTimeout * 0.25);\n const stabilityBudgetMs = Math.min(\n 2000,\n Math.max(300, stabilizationBudgetMs),\n );\n const deadline = Date.now() + stabilityBudgetMs;\n\n let actual: Buffer | undefined;\n let previous: Buffer | undefined;\n const pollIntervals = [0, 100, 250, 500];\n let isFirstIteration = true;\n\n // Retry screenshot up to 3 times\n // Otherwise sometimes the screenshot following a redirect may fail\n const safeScreenshot = async (): Promise<Buffer> => {\n for (let i = 0; i < 3; i++) {\n try {\n return await target.screenshot(options);\n } catch {\n await page.waitForTimeout(250);\n continue;\n }\n }\n return await target.screenshot(options);\n };\n\n while (true) {\n if (Date.now() >= deadline) {\n break;\n }\n const delay = pollIntervals.length ? pollIntervals.shift()! : 1000;\n if (delay) {\n await page.waitForTimeout(delay);\n }\n previous = actual;\n actual = await safeScreenshot();\n if (\n !isFirstIteration &&\n actual &&\n previous &&\n imagesAreSimilar({\n image1: previous,\n image2: actual,\n threshold: options?.threshold ?? 0.02,\n })\n ) {\n return actual;\n }\n isFirstIteration = false;\n }\n return actual ?? (await safeScreenshot());\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\n\nimport type { AgentResponse } from \"./agent/tool-responses\";\n\nimport { SDK_METADATA_HEADERS } from \"../../ai/metadata\";\nimport { requireApiKey } from \"../../runtime\";\nimport { takeStableScreenshot } from \"../../screenshot\";\nimport { truncate } from \"../../utils/truncate\";\nimport { constructAgentPayload } from \"./agent/construct-payload\";\nimport type { AgentActionResult } from \"./agent/exec-response\";\nimport { execResponse } from \"./agent/exec-response\";\nimport type { Model } from \"./agent/models\";\n\n/**\n * Options for configuring agent behavior during execution.\n */\ntype AgentActOptions = {\n /**\n * The page the agent will operate on.\n */\n page: Page;\n /**\n * Maximum number of thinking cycles the agent can perform.\n * Each cycle includes observing the page, planning, and executing one or more actions.\n * @default 30\n */\n maxCycles?: number;\n /**\n * AI model to use for agent reasoning.\n * Different models may have different capabilities and performance characteristics.\n */\n model?: Model;\n};\n\nconst AGENT_PATH = \"internal/v3/agent\";\n\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst AGENT_ENDPOINT = new URL(AGENT_PATH, STABLY_API_URL).toString();\n\n/**\n * AI agent for automating browser interactions using natural language.\n *\n * The Agent can perform complex browser actions by interpreting natural language instructions.\n * It observes the page state, makes decisions, and executes actions autonomously.\n *\n * Agents are created via {@link BrowserContext.newAgent} or {@link Browser.newAgent}.\n *\n * @example\n * ```typescript\n * const agent = context.newAgent();\n * await agent.act('Fill out the login form and submit', { page });\n * ```\n */\nexport class Agent {\n constructor(readonly browserContext: BrowserContext) {}\n\n /**\n * Instructs the agent to perform actions on the page using natural language.\n *\n * The agent will analyze the page, plan actions, and execute them autonomously.\n * It can perform multiple actions such as clicking, typing, navigating, and verifying\n * page state based on the provided instruction.\n *\n * @param prompt - Natural language instruction describing what the agent should do\n * @param options - Configuration for the agent's behavior including the page to operate on\n * @returns Promise that resolves when the agent successfully completes the task\n * @throws {Error} Throws an error if the agent fails to complete the task. The error message includes the AI's reasoning for the failure.\n *\n * @example\n * ```typescript\n * // Simple action\n * await agent.act('Click the login button', { page });\n *\n * // Complex multi-step action\n * await agent.act('Navigate to settings, enable notifications, and save changes', { page });\n *\n * // With custom options\n * await agent.act('Complete the checkout process', {\n * page,\n * maxCycles: 20,\n * model: 'gpt-4'\n * });\n *\n * // Handling failures with try-catch\n * try {\n * await agent.act('Complete the task', { page });\n * console.log('Agent completed the task successfully');\n * } catch (error) {\n * console.error('Agent failed:', error.message);\n * }\n * ```\n */\n async act(prompt: string, options: AgentActOptions): Promise<void> {\n const apiKey = requireApiKey();\n\n const maxCycles = options.maxCycles ?? 30;\n\n const tabManager = new Map<Page, string>();\n this.browserContext.pages().forEach((page, index) => {\n tabManager.set(page, `page${index + 1}`);\n });\n\n let activePage = options.page;\n let agentMessage: AgentActionResult = {\n isError: false,\n message: prompt,\n shouldTerminate: false,\n };\n let finalSuccess: boolean | undefined;\n let failureReason: string | undefined;\n let newPageOpenedMsg: string | undefined;\n\n const sessionId = crypto.randomUUID();\n\n const onNewPage = async (page: Page) => {\n await page.waitForLoadState(\"domcontentloaded\");\n if (!tabManager.has(page)) {\n const alias = `page${tabManager.size + 1}`;\n tabManager.set(page, alias);\n }\n await page.bringToFront();\n activePage = page;\n\n const alias = tabManager.get(page)!;\n newPageOpenedMsg = `opened new tab ${alias} (${page.url()})`;\n };\n\n this.browserContext.on(\"page\", onNewPage);\n\n return await test.step(`[Agent] ${prompt}`, async () => {\n try {\n for (let i = 0; i < maxCycles; i++) {\n if (agentMessage.shouldTerminate) {\n break;\n }\n\n const agentResponses =\n await test.step(`[Thinking ${i + 1}]`, async (stepInfo) => {\n const screenshot = await takeStableScreenshot(activePage);\n\n const response = await fetch(AGENT_ENDPOINT, {\n body: constructAgentPayload({\n activePage,\n additionalContext: newPageOpenedMsg\n ? { newPageMessage: newPageOpenedMsg }\n : undefined,\n isError: agentMessage.isError,\n message: agentMessage.message,\n model: options.model,\n screenshot,\n sessionId,\n tabManager,\n }),\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n // Clear any new page opened context after each agent call\n newPageOpenedMsg = undefined;\n const responseJson = (await response.json()) as AgentResponse[];\n\n if (!response.ok) {\n throw new Error(\n `Agent call failed: ${JSON.stringify(responseJson)}`\n );\n }\n\n // Extract and collect reasoning content from the responses\n const reasoningTexts = responseJson\n .map((r) => r.content?.trim())\n .filter((content) => content !== undefined);\n\n const reasoningText = reasoningTexts.join(\"\\n\\n\");\n\n // Only attach if there's actual reasoning content\n if (reasoningText) {\n const truncatedReasoningText = truncate(reasoningText, 120);\n\n await stepInfo.attach(\n `[Thinking ${i + 1}] ${truncatedReasoningText}`,\n {\n body: reasoningText,\n contentType: \"text/plain\",\n }\n );\n }\n\n return responseJson;\n });\n\n let combinedMessages: string[] = [];\n let aggregatedIsError = false;\n let aggregatedShouldTerminate = false;\n\n for (const agentResponse of agentResponses) {\n const {\n activePage: newActivePage,\n failureReason: maybeFailureReason,\n finalSuccess: maybeFinal,\n result,\n } = await execResponse({\n activePage,\n agentResponse,\n browserContext: this.browserContext,\n tabManager,\n });\n activePage = newActivePage;\n combinedMessages.push(result.message);\n finalSuccess = maybeFinal ?? finalSuccess;\n failureReason = maybeFailureReason ?? failureReason;\n if (result.isError) {\n aggregatedIsError = true;\n }\n if (result.shouldTerminate) {\n aggregatedShouldTerminate = true;\n break;\n }\n }\n\n agentMessage = {\n isError: aggregatedIsError,\n message: combinedMessages.join(\"\\n\"),\n shouldTerminate: aggregatedShouldTerminate,\n };\n }\n } finally {\n this.browserContext.off(\"page\", onNewPage);\n }\n\n const success = finalSuccess ?? false;\n if (!success) {\n throw new Error(failureReason ?? \"Agent failed to complete the task\");\n }\n });\n }\n}\n\nexport const createNewAgent = (browserContext: BrowserContext): Agent =>\n new Agent(browserContext);\n","export const truncate = (inp: string, length: number): string =>\n inp.length <= length || inp.length <= 3\n ? inp\n : `${inp.slice(0, length - 3)}...`;\n","import type { Page } from \"@playwright/test\";\nimport type { Model } from \"./models\";\n\nexport function constructAgentPayload({\n activePage,\n additionalContext,\n isError,\n message,\n model,\n screenshot,\n sessionId,\n tabManager,\n}: {\n sessionId: string;\n model?: Model;\n message: string;\n isError?: boolean;\n screenshot: Buffer;\n tabManager: Map<Page, string>;\n activePage: Page;\n additionalContext?: Record<string, unknown>;\n}): FormData {\n const form = new FormData();\n const viewportSize = activePage.viewportSize();\n\n const tabs = Array.from(tabManager.entries()).map(([page, alias]) => ({\n alias,\n url: page.url(),\n }));\n\n const activePageAlias = tabManager.get(activePage);\n\n const metadata: Record<string, unknown> = {\n allPages: tabs,\n message,\n sessionId,\n };\n\n if (model) {\n metadata.model = model;\n }\n if (isError) {\n metadata.isError = isError;\n }\n if (additionalContext) {\n metadata.additionalContext = additionalContext;\n }\n if (viewportSize) {\n metadata.pageDimensions = viewportSize;\n }\n if (activePageAlias) {\n metadata.activePageAlias = activePageAlias;\n }\n\n const metadataBlob = new Blob([JSON.stringify(metadata)], {\n type: \"application/json\",\n });\n form.append(\"metadata\", metadataBlob, \"metadata.json\");\n\n const screenshotBytes = Uint8Array.from(screenshot);\n const screenshotBlob = new Blob([screenshotBytes], { type: \"image/png\" });\n form.append(\"screenshot\", screenshotBlob, \"screenshot.png\");\n\n return form;\n}\n","import type { BrowserContext, Page } from \"@playwright/test\";\n\nimport { takeStableScreenshot } from \"../../../screenshot\";\nimport type { AgentResponse } from \"./tool-responses\";\n\nexport type AgentActionResult = {\n message: string;\n isError?: boolean;\n shouldTerminate?: boolean;\n};\n\ntype PageWithSnapshot = Page & {\n _snapshotForAI: () => string;\n};\n\nconst DEFAULT_AGENT_WAIT_MS = 3000;\n\nexport async function execResponse({\n activePage: initialActivePage,\n agentResponse,\n browserContext,\n tabManager,\n}: {\n activePage: Page;\n agentResponse: AgentResponse;\n browserContext: BrowserContext;\n tabManager: Map<Page, string>;\n}): Promise<{\n activePage: Page;\n finalSuccess?: boolean;\n failureReason?: string;\n result: AgentActionResult;\n}> {\n let activePage = initialActivePage;\n try {\n switch (agentResponse.action) {\n case \"key\": {\n const { text } = agentResponse;\n if (text) {\n await activePage.keyboard.press(text);\n return { activePage, result: { message: `pressed \"${text}\"` } };\n }\n return { activePage, result: { message: \"pressed key\" } };\n }\n case \"type\": {\n const { text } = agentResponse;\n await activePage.keyboard.type(text);\n return { activePage, result: { message: `typed \"${text}\"` } };\n }\n case \"mouse_move\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n return { activePage, result: { message: `mouse moved completed` } };\n }\n case \"left_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y);\n return { activePage, result: { message: `left click completed` } };\n }\n case \"right_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { button: \"right\" });\n return { activePage, result: { message: `right click completed` } };\n }\n case \"double_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.dblclick(x, y);\n return { activePage, result: { message: `double click completed` } };\n }\n case \"triple_click\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.click(x, y, { clickCount: 3 });\n return { activePage, result: { message: `triple click completed` } };\n }\n case \"left_click_drag\": {\n const [startX, startY] = agentResponse.start_coordinate;\n const [endX, endY] = agentResponse.coordinate;\n await activePage.mouse.move(startX, startY);\n await activePage.mouse.down();\n await activePage.mouse.move(endX, endY);\n await activePage.mouse.up();\n return { activePage, result: { message: `drag completed` } };\n }\n case \"screenshot\": {\n await takeStableScreenshot(activePage);\n return { activePage, result: { message: \"captured screenshot\" } };\n }\n case \"wait\": {\n const waitMs = agentResponse.milliseconds ?? DEFAULT_AGENT_WAIT_MS;\n await activePage.waitForTimeout(waitMs);\n return { activePage, result: { message: `waited ${waitMs}ms` } };\n }\n case \"navigate_to_url\": {\n await activePage.goto(agentResponse.url);\n return {\n activePage,\n result: { message: `navigated to \"${agentResponse.url}\"` },\n };\n }\n case \"new_tab_url\": {\n const newPage = await browserContext.newPage();\n await newPage.goto(agentResponse.url);\n await newPage.waitForLoadState(\"domcontentloaded\");\n activePage = newPage;\n return { activePage, result: { message: \"opened new tab\" } };\n }\n case \"switch_tab\": {\n const entry = Array.from(tabManager.entries()).find(\n ([, alias]) => alias === agentResponse.tab_alias,\n );\n const page = entry?.[0];\n if (!page) {\n throw new Error(\n `Tab with alias ${agentResponse.tab_alias} not found`,\n );\n }\n await page.bringToFront();\n activePage = page;\n return {\n activePage,\n result: { message: `switched to \"${agentResponse.tab_alias}\"` },\n };\n }\n case \"scroll\": {\n const [x, y] = agentResponse.coordinate;\n await activePage.mouse.move(x, y);\n let deltaX = 0;\n let deltaY = 0;\n switch (agentResponse.scroll_direction) {\n case \"up\":\n deltaY = -agentResponse.scroll_amount;\n break;\n case \"down\":\n deltaY = agentResponse.scroll_amount;\n break;\n case \"left\":\n deltaX = -agentResponse.scroll_amount;\n break;\n case \"right\":\n deltaX = agentResponse.scroll_amount;\n break;\n }\n await activePage.mouse.wheel(deltaX, deltaY);\n return {\n activePage,\n result: { message: `scrolled ${agentResponse.scroll_direction}` },\n };\n }\n case \"navigate_back\": {\n const res = await activePage.goBack();\n if (!res) {\n throw new Error(\"navigate_back failed: no history entry\");\n }\n return { activePage, result: { message: \"navigated back\" } };\n }\n case \"aria_snapshot\": {\n const ariaSnapshot = await (\n activePage as PageWithSnapshot\n )._snapshotForAI();\n return {\n activePage,\n result: { message: `ARIA Snapshot:\\n${ariaSnapshot}` },\n };\n }\n case \"terminate_test\": {\n const { reason, success } = agentResponse;\n return {\n activePage,\n failureReason: success ? undefined : reason,\n finalSuccess: success,\n result: { message: reason, shouldTerminate: true },\n };\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { activePage, result: { isError: true, message } };\n }\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport { test } from \"@playwright/test\";\nimport type * as z4 from \"zod/v4/core\";\n\nimport { requireApiKey } from \"../runtime\";\nimport { isObject } from \"../type-predicate/is-object\";\nimport { SDK_METADATA_HEADERS } from \"./metadata\";\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\ntype ZodV4 = typeof import(\"zod/v4/core\");\n\nexport type ExtractSchema = {\n safeParseAsync(\n data: unknown,\n params?: z4.ParseContext<z4.$ZodIssue>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<z4.util.SafeParseResult<z4.output<any>>>;\n} & z4.$ZodType;\n\nexport type SchemaOutput<T extends ExtractSchema> = z4.output<T>;\n\ntype ExtractIssue = z4.$ZodIssue;\n\nconst EXTRACT_PATH = \"internal/v2/extract\";\nconst STABLY_API_URL = process.env.STABLY_API_URL || \"https://api.stably.ai\";\nconst EXTRACT_ENDPOINT = new URL(EXTRACT_PATH, STABLY_API_URL).toString();\n\nconst zodV4: ZodV4 | undefined = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n return require(\"zod/v4/core\") as ZodV4;\n } catch {\n return undefined;\n }\n})();\n\ntype ExtractionSuccess = { success: true; value: unknown };\ntype ExtractionFailure = { success: false; error: string };\ntype ExtractionResponse = ExtractionSuccess | ExtractionFailure;\n\ntype ErrorResponse = { error: string };\n\nconst isExtractionResponse = (value: unknown): value is ExtractionResponse => {\n if (!isObject(value)) {\n return false;\n }\n\n if (value.success === true) {\n return \"value\" in value;\n }\n\n return value.success === false && typeof value.error === \"string\";\n};\n\nconst isErrorResponse = (value: unknown): value is ErrorResponse => {\n return isObject(value) && typeof value.error === \"string\";\n};\n\nclass ExtractValidationError extends Error {\n constructor(\n message: string,\n readonly issues: readonly ExtractIssue[],\n ) {\n super(message);\n this.name = \"ExtractValidationError\";\n }\n}\n\nasync function validateWithSchema<T extends ExtractSchema>(\n schema: T,\n value: unknown,\n): Promise<SchemaOutput<T>> {\n const result = await schema.safeParseAsync(value);\n if (!result.success) {\n throw new ExtractValidationError(\n \"AI is unable to return the data in the desired format\",\n result.error.issues,\n );\n }\n\n return result.data;\n}\n\ntype BaseExtractArgs = {\n prompt: string;\n pageOrLocator: Page | Locator;\n};\n\ntype ExtractArgsWithSchema<T extends ExtractSchema> = BaseExtractArgs & {\n schema: T;\n};\n\nexport async function extract(args: BaseExtractArgs): Promise<string>;\nexport async function extract<T extends ExtractSchema>(\n args: ExtractArgsWithSchema<T>,\n): Promise<SchemaOutput<T>>;\nexport async function extract<T extends ExtractSchema>({\n pageOrLocator,\n prompt,\n schema,\n}: BaseExtractArgs & { schema?: T }): Promise<string | SchemaOutput<T>> {\n if (schema && !zodV4) {\n throw new Error(\n \"Schema support requires installing zod@4. Please add it to enable schemas.\",\n );\n }\n\n const jsonSchema =\n schema && zodV4\n ? zodV4?.toJSONSchema(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n schema as unknown as Parameters<ZodV4[\"toJSONSchema\"]>[0],\n )\n : undefined;\n\n return await test.step(`[Extract] ${prompt}`, async (stepInfo) => {\n const apiKey = requireApiKey();\n\n const form = new FormData();\n form.append(\"prompt\", prompt);\n if (jsonSchema) {\n form.append(\"jsonSchema\", JSON.stringify(jsonSchema));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const pngBuffer = await (pageOrLocator as any).screenshot({ type: \"png\" }); // Buffer\n const u8 = Uint8Array.from(pngBuffer); // strips Buffer type → plain Uint8Array\n const blob = new Blob([u8], { type: \"image/png\" });\n form.append(\"image\", blob, \"screenshot.png\");\n\n const response = await fetch(EXTRACT_ENDPOINT, {\n body: form,\n headers: {\n ...SDK_METADATA_HEADERS,\n Authorization: `Bearer ${apiKey}`,\n },\n method: \"POST\",\n });\n\n const raw = await response.json().catch(() => undefined as unknown);\n\n if (response.ok) {\n if (!isExtractionResponse(raw)) {\n throw new Error(\"Extract returned unexpected response shape\");\n }\n\n if (!raw.success) {\n await stepInfo.attach(\"[Extract] error\", {\n body: raw.error,\n contentType: \"text/plain\",\n });\n throw new Error(`Extract failed: ${raw.error}`);\n }\n\n const { value } = raw;\n const body =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n await stepInfo.attach(\"[Extract] result\", {\n body,\n contentType: \"text/plain\",\n });\n\n return schema\n ? await validateWithSchema(schema, value)\n : typeof value === \"string\"\n ? value\n : JSON.stringify(value);\n }\n\n throw new Error(isErrorResponse(raw) ? raw.error : \"Extract failed\");\n });\n}\n","import type { Locator, Page } from \"@playwright/test\";\n\nimport {\n type ExtractSchema,\n type SchemaOutput,\n extract,\n} from \"../../ai/extract\";\n\ntype ExtractOptions<T extends ExtractSchema> = {\n schema: T;\n};\n\ntype ExtractMethod = {\n (prompt: string): Promise<string>;\n <T extends ExtractSchema>(\n prompt: string,\n options: ExtractOptions<T>,\n ): Promise<SchemaOutput<T>>;\n};\n\ntype LocatorExtract = ExtractMethod;\ntype PageExtract = ExtractMethod;\n\ntype ExtractSubject = Locator | Page;\n\nfunction createExtract(pageOrLocator: ExtractSubject): ExtractMethod {\n const impl = (async (\n prompt: string,\n options?: ExtractOptions<ExtractSchema>,\n ) => {\n if (options?.schema) {\n return extract({\n pageOrLocator,\n prompt,\n schema: options.schema,\n });\n }\n\n return extract({ pageOrLocator, prompt });\n }) as ExtractMethod;\n\n return impl;\n}\n\nexport const createLocatorExtract = (locator: Locator): LocatorExtract =>\n createExtract(locator);\n\nexport const createPageExtract = (page: Page): PageExtract =>\n createExtract(page);\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */\nimport type {\n Browser,\n BrowserContext,\n BrowserType,\n Locator,\n Page,\n} from \"@playwright/test\";\n\nimport { createNewAgent } from \"./methods/agent\";\nimport { createLocatorExtract, createPageExtract } from \"./methods/extract\";\n\nconst LOCATOR_PATCHED = Symbol.for(\"stably.playwright.locatorPatched\");\nconst PAGE_PATCHED = Symbol.for(\"stably.playwright.pagePatched\");\nconst CONTEXT_PATCHED = Symbol.for(\"stably.playwright.contextPatched\");\nconst BROWSER_PATCHED = Symbol.for(\"stably.playwright.browserPatched\");\nconst BROWSER_TYPE_PATCHED = Symbol.for(\"stably.playwright.browserTypePatched\");\n\nfunction defineHiddenProperty<T, K extends PropertyKey>(\n target: T,\n key: K,\n value: unknown,\n): void {\n Object.defineProperty(target as unknown as object, key, {\n configurable: true,\n enumerable: false,\n value,\n writable: true,\n });\n}\n\nexport function augmentLocator<T extends Locator>(locator: T): T {\n if (\n (locator as unknown as { [LOCATOR_PATCHED]?: boolean })[LOCATOR_PATCHED]\n ) {\n return locator;\n }\n\n defineHiddenProperty(locator, \"extract\", createLocatorExtract(locator));\n\n defineHiddenProperty(locator, LOCATOR_PATCHED, true);\n\n return locator;\n}\n\nexport function augmentPage<T extends Page>(page: T): T {\n if ((page as unknown as { [PAGE_PATCHED]?: boolean })[PAGE_PATCHED]) {\n return page;\n }\n\n const originalLocator = (page as any).locator.bind(page);\n (page as any).locator = ((...args: any[]) => {\n const locator = originalLocator(...args);\n return augmentLocator(locator);\n }) as any;\n\n defineHiddenProperty(page, \"extract\", createPageExtract(page));\n defineHiddenProperty(page, PAGE_PATCHED, true);\n\n return page;\n}\n\nexport function augmentBrowserContext<T extends BrowserContext>(context: T): T {\n if (\n (context as unknown as { [CONTEXT_PATCHED]?: boolean })[CONTEXT_PATCHED]\n ) {\n return context;\n }\n\n const originalNewPage = (context as any).newPage.bind(context);\n (context as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalPages = (context as any).pages?.bind(context);\n if (originalPages) {\n (context as any).pages = (() =>\n originalPages().map((page: Page) => augmentPage(page))) as any;\n }\n\n if (!(context as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(context, \"newAgent\", () => {\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(context, CONTEXT_PATCHED, true);\n\n return context;\n}\n\nexport function augmentBrowser<T extends Browser>(browser: T): T {\n if (\n (browser as unknown as { [BROWSER_PATCHED]?: boolean })[BROWSER_PATCHED]\n ) {\n return browser;\n }\n\n const originalNewContext = (browser as any).newContext.bind(browser);\n (browser as any).newContext = (async (...args: any[]) => {\n const context = await originalNewContext(...args);\n return augmentBrowserContext(context);\n }) as any;\n\n const originalNewPage = (browser as any).newPage.bind(browser);\n (browser as any).newPage = (async (...args: any[]) => {\n const page = await originalNewPage(...args);\n return augmentPage(page);\n }) as any;\n\n const originalContexts = (browser as any).contexts.bind(browser);\n (browser as any).contexts = (() =>\n originalContexts().map((context: BrowserContext) =>\n augmentBrowserContext(context),\n )) as any;\n\n if (!(browser as unknown as { newAgent?: unknown }).newAgent) {\n defineHiddenProperty(browser, \"newAgent\", () => {\n // Get the first context, or it will be created when the agent tries to access browserContext\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : browser.contexts()[0];\n return createNewAgent(context);\n });\n }\n\n defineHiddenProperty(browser, BROWSER_PATCHED, true);\n\n return browser;\n}\n\nexport function augmentBrowserType<TBrowser extends Browser>(\n browserType: BrowserType<TBrowser>,\n): BrowserType<TBrowser> {\n if (\n (browserType as unknown as { [BROWSER_TYPE_PATCHED]?: boolean })[\n BROWSER_TYPE_PATCHED\n ]\n ) {\n return browserType;\n }\n\n const originalLaunch = (browserType as any).launch.bind(browserType);\n (browserType as any).launch = (async (\n ...args: Parameters<BrowserType<TBrowser>[\"launch\"]>\n ) => {\n const browser = await originalLaunch(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as BrowserType<TBrowser>[\"launch\"];\n\n const originalConnect = (browserType as any).connect?.bind(browserType);\n if (originalConnect) {\n (browserType as any).connect = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connect\"]>>\n ) => {\n const browser = await originalConnect(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connect\"]>;\n }\n\n const originalConnectOverCDP = (browserType as any).connectOverCDP?.bind(\n browserType,\n );\n if (originalConnectOverCDP) {\n (browserType as any).connectOverCDP = (async (\n ...args: Parameters<NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>>\n ) => {\n const browser = await originalConnectOverCDP(...args);\n return augmentBrowser(browser) as TBrowser;\n }) as unknown as NonNullable<BrowserType<TBrowser>[\"connectOverCDP\"]>;\n }\n\n const originalLaunchPersistentContext = (\n browserType as any\n ).launchPersistentContext?.bind(browserType);\n if (originalLaunchPersistentContext) {\n (browserType as any).launchPersistentContext = (async (\n ...args: Parameters<\n NonNullable<BrowserType<TBrowser>[\"launchPersistentContext\"]>\n >\n ) => {\n const context = await originalLaunchPersistentContext(...args);\n return augmentBrowserContext(context) as BrowserContext;\n }) as unknown as NonNullable<\n BrowserType<TBrowser>[\"launchPersistentContext\"]\n >;\n }\n\n defineHiddenProperty(browserType, BROWSER_TYPE_PATCHED, true);\n\n return browserType;\n}\n"],"mappings":"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","names":["png","test","STABLY_API_URL","alias","test","test","STABLY_API_URL","test"]}
|