forked from GitHubMirrors/silverbullet-icalendar
Cleanup: Remove unnecessary Library folder and keep plug files at root
All checks were successful
Build SilverBullet Plug / build (push) Successful in 31s
All checks were successful
Build SilverBullet Plug / build (push) Successful in 31s
This commit is contained in:
335
node_modules/playwright-core/lib/server/agent/actionRunner.js
generated
vendored
Normal file
335
node_modules/playwright-core/lib/server/agent/actionRunner.js
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var actionRunner_exports = {};
|
||||
__export(actionRunner_exports, {
|
||||
runAction: () => runAction,
|
||||
traceParamsForAction: () => traceParamsForAction
|
||||
});
|
||||
module.exports = __toCommonJS(actionRunner_exports);
|
||||
var import_expectUtils = require("../utils/expectUtils");
|
||||
var import_urlMatch = require("../../utils/isomorphic/urlMatch");
|
||||
var import_stringUtils = require("../../utils/isomorphic/stringUtils");
|
||||
var import_time = require("../../utils/isomorphic/time");
|
||||
var import_crypto = require("../utils/crypto");
|
||||
var import_ariaSnapshot = require("../../utils/isomorphic/ariaSnapshot");
|
||||
var import_locatorGenerators = require("../../utils/isomorphic/locatorGenerators");
|
||||
var import_utilsBundle = require("../../utilsBundle");
|
||||
var import_errors = require("../errors");
|
||||
async function runAction(progress, mode, page, action, secrets) {
|
||||
const parentMetadata = progress.metadata;
|
||||
const frame = page.mainFrame();
|
||||
const callMetadata = callMetadataForAction(progress, frame, action, mode);
|
||||
callMetadata.log = parentMetadata.log;
|
||||
progress.metadata = callMetadata;
|
||||
await frame.instrumentation.onBeforeCall(frame, callMetadata, parentMetadata.id);
|
||||
let error;
|
||||
const result = await innerRunAction(progress, mode, page, action, secrets).catch((e) => error = e);
|
||||
callMetadata.endTime = (0, import_time.monotonicTime)();
|
||||
callMetadata.error = error ? (0, import_errors.serializeError)(error) : void 0;
|
||||
callMetadata.result = error ? void 0 : result;
|
||||
await frame.instrumentation.onAfterCall(frame, callMetadata);
|
||||
if (error)
|
||||
throw error;
|
||||
return result;
|
||||
}
|
||||
async function innerRunAction(progress, mode, page, action, secrets) {
|
||||
const frame = page.mainFrame();
|
||||
const commonOptions = { strict: true, noAutoWaiting: mode === "generate" };
|
||||
switch (action.method) {
|
||||
case "navigate":
|
||||
await frame.goto(progress, action.url);
|
||||
break;
|
||||
case "click":
|
||||
await frame.click(progress, action.selector, {
|
||||
button: action.button,
|
||||
clickCount: action.clickCount,
|
||||
modifiers: action.modifiers,
|
||||
...commonOptions
|
||||
});
|
||||
break;
|
||||
case "drag":
|
||||
await frame.dragAndDrop(progress, action.sourceSelector, action.targetSelector, { ...commonOptions });
|
||||
break;
|
||||
case "hover":
|
||||
await frame.hover(progress, action.selector, {
|
||||
modifiers: action.modifiers,
|
||||
...commonOptions
|
||||
});
|
||||
break;
|
||||
case "selectOption":
|
||||
await frame.selectOption(progress, action.selector, [], action.labels.map((a) => ({ label: a })), { ...commonOptions });
|
||||
break;
|
||||
case "pressKey":
|
||||
await page.keyboard.press(progress, action.key);
|
||||
break;
|
||||
case "pressSequentially": {
|
||||
const secret = secrets?.find((s) => s.name === action.text)?.value ?? action.text;
|
||||
await frame.type(progress, action.selector, secret, { ...commonOptions });
|
||||
if (action.submit)
|
||||
await page.keyboard.press(progress, "Enter");
|
||||
break;
|
||||
}
|
||||
case "fill": {
|
||||
const secret = secrets?.find((s) => s.name === action.text)?.value ?? action.text;
|
||||
await frame.fill(progress, action.selector, secret, { ...commonOptions });
|
||||
if (action.submit)
|
||||
await page.keyboard.press(progress, "Enter");
|
||||
break;
|
||||
}
|
||||
case "setChecked":
|
||||
if (action.checked)
|
||||
await frame.check(progress, action.selector, { ...commonOptions });
|
||||
else
|
||||
await frame.uncheck(progress, action.selector, { ...commonOptions });
|
||||
break;
|
||||
case "expectVisible": {
|
||||
await runExpect(frame, progress, mode, action.selector, { expression: "to.be.visible", isNot: !!action.isNot }, "visible", "toBeVisible", "");
|
||||
break;
|
||||
}
|
||||
case "expectValue": {
|
||||
if (action.type === "textbox" || action.type === "combobox" || action.type === "slider") {
|
||||
const expectedText = (0, import_expectUtils.serializeExpectedTextValues)([action.value]);
|
||||
await runExpect(frame, progress, mode, action.selector, { expression: "to.have.value", expectedText, isNot: !!action.isNot }, action.value, "toHaveValue", "expected");
|
||||
} else if (action.type === "checkbox" || action.type === "radio") {
|
||||
const expectedValue = { checked: action.value === "true" };
|
||||
await runExpect(frame, progress, mode, action.selector, { selector: action.selector, expression: "to.be.checked", expectedValue, isNot: !!action.isNot }, action.value ? "checked" : "unchecked", "toBeChecked", "");
|
||||
} else {
|
||||
throw new Error(`Unsupported element type: ${action.type}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "expectAria": {
|
||||
const expectedValue = (0, import_ariaSnapshot.parseAriaSnapshotUnsafe)(import_utilsBundle.yaml, action.template);
|
||||
await runExpect(frame, progress, mode, "body", { expression: "to.match.aria", expectedValue, isNot: !!action.isNot }, "\n" + action.template, "toMatchAriaSnapshot", "expected");
|
||||
break;
|
||||
}
|
||||
case "expectURL": {
|
||||
if (!action.regex && !action.value)
|
||||
throw new Error("Either url or regex must be provided");
|
||||
if (action.regex && action.value)
|
||||
throw new Error("Only one of url or regex can be provided");
|
||||
const expected = action.regex ? (0, import_stringUtils.parseRegex)(action.regex) : (0, import_urlMatch.constructURLBasedOnBaseURL)(page.browserContext._options.baseURL, action.value);
|
||||
const expectedText = (0, import_expectUtils.serializeExpectedTextValues)([expected]);
|
||||
await runExpect(frame, progress, mode, void 0, { expression: "to.have.url", expectedText, isNot: !!action.isNot }, expected, "toHaveURL", "expected");
|
||||
break;
|
||||
}
|
||||
case "expectTitle": {
|
||||
const expectedText = (0, import_expectUtils.serializeExpectedTextValues)([action.value], { normalizeWhiteSpace: true });
|
||||
await runExpect(frame, progress, mode, void 0, { expression: "to.have.title", expectedText, isNot: !!action.isNot }, action.value, "toHaveTitle", "expected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
async function runExpect(frame, progress, mode, selector, options, expected, matcherName, expectation) {
|
||||
const result = await frame.expect(progress, selector, {
|
||||
...options,
|
||||
// When generating, we want the expect to pass or fail immediately and give feedback to the model.
|
||||
noAutoWaiting: mode === "generate",
|
||||
timeoutForLogs: mode === "generate" ? void 0 : progress.timeout
|
||||
});
|
||||
if (!result.matches === !options.isNot) {
|
||||
const received = matcherName === "toMatchAriaSnapshot" ? "\n" + result.received.raw : result.received;
|
||||
const expectedSuffix = typeof expected === "string" ? "" : " pattern";
|
||||
const expectedDisplay = typeof expected === "string" ? expected : expected.toString();
|
||||
throw new Error((0, import_expectUtils.formatMatcherMessage)(import_expectUtils.simpleMatcherUtils, {
|
||||
isNot: options.isNot,
|
||||
matcherName,
|
||||
expectation,
|
||||
locator: selector ? (0, import_locatorGenerators.asLocatorDescription)("javascript", selector) : void 0,
|
||||
timedOut: result.timedOut,
|
||||
timeout: mode === "generate" ? void 0 : progress.timeout,
|
||||
printedExpected: options.isNot ? `Expected${expectedSuffix}: not ${expectedDisplay}` : `Expected${expectedSuffix}: ${expectedDisplay}`,
|
||||
printedReceived: result.errorMessage ? "" : `Received: ${received}`,
|
||||
errorMessage: result.errorMessage
|
||||
// Note: we are not passing call log, because it will be automatically appended on the client side,
|
||||
// as a part of the agent.{perform,expect} call.
|
||||
}));
|
||||
}
|
||||
}
|
||||
function traceParamsForAction(progress, action, mode) {
|
||||
const timeout = progress.timeout;
|
||||
switch (action.method) {
|
||||
case "navigate": {
|
||||
const params = {
|
||||
url: action.url,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "goto", params };
|
||||
}
|
||||
case "click": {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
strict: true,
|
||||
modifiers: action.modifiers,
|
||||
button: action.button,
|
||||
clickCount: action.clickCount,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "click", params };
|
||||
}
|
||||
case "drag": {
|
||||
const params = {
|
||||
source: action.sourceSelector,
|
||||
target: action.targetSelector,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "dragAndDrop", params };
|
||||
}
|
||||
case "hover": {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
modifiers: action.modifiers,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "hover", params };
|
||||
}
|
||||
case "pressKey": {
|
||||
const params = {
|
||||
key: action.key
|
||||
};
|
||||
return { type: "Page", method: "keyboardPress", params };
|
||||
}
|
||||
case "pressSequentially": {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
text: action.text,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "type", params };
|
||||
}
|
||||
case "fill": {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
strict: true,
|
||||
value: action.text,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "fill", params };
|
||||
}
|
||||
case "setChecked": {
|
||||
if (action.checked) {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
strict: true,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "check", params };
|
||||
} else {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
strict: true,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "uncheck", params };
|
||||
}
|
||||
}
|
||||
case "selectOption": {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
strict: true,
|
||||
options: action.labels.map((label) => ({ label })),
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "selectOption", params };
|
||||
}
|
||||
case "expectValue": {
|
||||
if (action.type === "textbox" || action.type === "combobox" || action.type === "slider") {
|
||||
const expectedText = (0, import_expectUtils.serializeExpectedTextValues)([action.value]);
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
expression: "to.have.value",
|
||||
expectedText,
|
||||
isNot: !!action.isNot,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "expect", title: "Expect Value", params };
|
||||
} else if (action.type === "checkbox" || action.type === "radio") {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
expression: "to.be.checked",
|
||||
isNot: !!action.isNot,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "expect", title: "Expect Checked", params };
|
||||
} else {
|
||||
throw new Error(`Unsupported element type: ${action.type}`);
|
||||
}
|
||||
}
|
||||
case "expectVisible": {
|
||||
const params = {
|
||||
selector: action.selector,
|
||||
expression: "to.be.visible",
|
||||
isNot: !!action.isNot,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "expect", title: "Expect Visible", params };
|
||||
}
|
||||
case "expectAria": {
|
||||
const params = {
|
||||
selector: "body",
|
||||
expression: "to.match.snapshot",
|
||||
expectedText: [],
|
||||
isNot: !!action.isNot,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "expect", title: "Expect Aria Snapshot", params };
|
||||
}
|
||||
case "expectURL": {
|
||||
const expected = action.regex ? (0, import_stringUtils.parseRegex)(action.regex) : action.value;
|
||||
const expectedText = (0, import_expectUtils.serializeExpectedTextValues)([expected]);
|
||||
const params = {
|
||||
selector: void 0,
|
||||
expression: "to.have.url",
|
||||
expectedText,
|
||||
isNot: !!action.isNot,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "expect", title: "Expect URL", params };
|
||||
}
|
||||
case "expectTitle": {
|
||||
const expectedText = (0, import_expectUtils.serializeExpectedTextValues)([action.value], { normalizeWhiteSpace: true });
|
||||
const params = {
|
||||
selector: void 0,
|
||||
expression: "to.have.title",
|
||||
expectedText,
|
||||
isNot: !!action.isNot,
|
||||
timeout
|
||||
};
|
||||
return { type: "Frame", method: "expect", title: "Expect Title", params };
|
||||
}
|
||||
}
|
||||
}
|
||||
function callMetadataForAction(progress, frame, action, mode) {
|
||||
const callMetadata = {
|
||||
id: `call@${(0, import_crypto.createGuid)()}`,
|
||||
objectId: frame.guid,
|
||||
pageId: frame._page.guid,
|
||||
frameId: frame.guid,
|
||||
startTime: (0, import_time.monotonicTime)(),
|
||||
endTime: 0,
|
||||
log: [],
|
||||
...traceParamsForAction(progress, action, mode)
|
||||
};
|
||||
return callMetadata;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
runAction,
|
||||
traceParamsForAction
|
||||
});
|
||||
128
node_modules/playwright-core/lib/server/agent/actions.js
generated
vendored
Normal file
128
node_modules/playwright-core/lib/server/agent/actions.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var actions_exports = {};
|
||||
__export(actions_exports, {
|
||||
cachedActionsSchema: () => cachedActionsSchema
|
||||
});
|
||||
module.exports = __toCommonJS(actions_exports);
|
||||
var import_mcpBundle = require("../../mcpBundle");
|
||||
const modifiersSchema = import_mcpBundle.z.array(
|
||||
import_mcpBundle.z.enum(["Alt", "Control", "ControlOrMeta", "Meta", "Shift"])
|
||||
);
|
||||
const navigateActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("navigate"),
|
||||
url: import_mcpBundle.z.string()
|
||||
});
|
||||
const clickActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("click"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
button: import_mcpBundle.z.enum(["left", "right", "middle"]).optional(),
|
||||
clickCount: import_mcpBundle.z.number().optional(),
|
||||
modifiers: modifiersSchema.optional()
|
||||
});
|
||||
const dragActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("drag"),
|
||||
sourceSelector: import_mcpBundle.z.string(),
|
||||
targetSelector: import_mcpBundle.z.string()
|
||||
});
|
||||
const hoverActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("hover"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
modifiers: modifiersSchema.optional()
|
||||
});
|
||||
const selectOptionActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("selectOption"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
labels: import_mcpBundle.z.array(import_mcpBundle.z.string())
|
||||
});
|
||||
const pressActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("pressKey"),
|
||||
key: import_mcpBundle.z.string()
|
||||
});
|
||||
const pressSequentiallyActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("pressSequentially"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
text: import_mcpBundle.z.string(),
|
||||
submit: import_mcpBundle.z.boolean().optional()
|
||||
});
|
||||
const fillActionSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("fill"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
text: import_mcpBundle.z.string(),
|
||||
submit: import_mcpBundle.z.boolean().optional()
|
||||
});
|
||||
const setCheckedSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("setChecked"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
checked: import_mcpBundle.z.boolean()
|
||||
});
|
||||
const expectVisibleSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("expectVisible"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
isNot: import_mcpBundle.z.boolean().optional()
|
||||
});
|
||||
const expectValueSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("expectValue"),
|
||||
selector: import_mcpBundle.z.string(),
|
||||
type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]),
|
||||
value: import_mcpBundle.z.string(),
|
||||
isNot: import_mcpBundle.z.boolean().optional()
|
||||
});
|
||||
const expectAriaSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("expectAria"),
|
||||
template: import_mcpBundle.z.string(),
|
||||
isNot: import_mcpBundle.z.boolean().optional()
|
||||
});
|
||||
const expectURLSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("expectURL"),
|
||||
value: import_mcpBundle.z.string().optional(),
|
||||
regex: import_mcpBundle.z.string().optional(),
|
||||
isNot: import_mcpBundle.z.boolean().optional()
|
||||
});
|
||||
const expectTitleSchema = import_mcpBundle.z.object({
|
||||
method: import_mcpBundle.z.literal("expectTitle"),
|
||||
value: import_mcpBundle.z.string(),
|
||||
isNot: import_mcpBundle.z.boolean().optional()
|
||||
});
|
||||
const actionSchema = import_mcpBundle.z.discriminatedUnion("method", [
|
||||
navigateActionSchema,
|
||||
clickActionSchema,
|
||||
dragActionSchema,
|
||||
hoverActionSchema,
|
||||
selectOptionActionSchema,
|
||||
pressActionSchema,
|
||||
pressSequentiallyActionSchema,
|
||||
fillActionSchema,
|
||||
setCheckedSchema,
|
||||
expectVisibleSchema,
|
||||
expectValueSchema,
|
||||
expectAriaSchema,
|
||||
expectURLSchema,
|
||||
expectTitleSchema
|
||||
]);
|
||||
const actionWithCodeSchema = actionSchema.and(import_mcpBundle.z.object({
|
||||
code: import_mcpBundle.z.string()
|
||||
}));
|
||||
const cachedActionsSchema = import_mcpBundle.z.record(import_mcpBundle.z.string(), import_mcpBundle.z.object({
|
||||
actions: import_mcpBundle.z.array(actionWithCodeSchema)
|
||||
}));
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
cachedActionsSchema
|
||||
});
|
||||
111
node_modules/playwright-core/lib/server/agent/codegen.js
generated
vendored
Normal file
111
node_modules/playwright-core/lib/server/agent/codegen.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var codegen_exports = {};
|
||||
__export(codegen_exports, {
|
||||
generateCode: () => generateCode
|
||||
});
|
||||
module.exports = __toCommonJS(codegen_exports);
|
||||
var import_locatorGenerators = require("../../utils/isomorphic/locatorGenerators");
|
||||
var import_stringUtils = require("../../utils/isomorphic/stringUtils");
|
||||
async function generateCode(sdkLanguage, action) {
|
||||
switch (action.method) {
|
||||
case "navigate": {
|
||||
return `await page.goto(${(0, import_stringUtils.escapeWithQuotes)(action.url)});`;
|
||||
}
|
||||
case "click": {
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
return `await page.${locator}.click(${(0, import_stringUtils.formatObjectOrVoid)({
|
||||
button: action.button,
|
||||
clickCount: action.clickCount,
|
||||
modifiers: action.modifiers
|
||||
})});`;
|
||||
}
|
||||
case "drag": {
|
||||
const sourceLocator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.sourceSelector);
|
||||
const targetLocator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.targetSelector);
|
||||
return `await page.${sourceLocator}.dragAndDrop(${targetLocator});`;
|
||||
}
|
||||
case "hover": {
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
return `await page.${locator}.hover(${(0, import_stringUtils.formatObjectOrVoid)({
|
||||
modifiers: action.modifiers
|
||||
})});`;
|
||||
}
|
||||
case "pressKey": {
|
||||
return `await page.keyboard.press(${(0, import_stringUtils.escapeWithQuotes)(action.key, "'")});`;
|
||||
}
|
||||
case "selectOption": {
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
return `await page.${locator}.selectOption(${action.labels.length === 1 ? (0, import_stringUtils.escapeWithQuotes)(action.labels[0]) : "[" + action.labels.map((label) => (0, import_stringUtils.escapeWithQuotes)(label)).join(", ") + "]"});`;
|
||||
}
|
||||
case "pressSequentially": {
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
const code = [`await page.${locator}.pressSequentially(${(0, import_stringUtils.escapeWithQuotes)(action.text)});`];
|
||||
if (action.submit)
|
||||
code.push(`await page.keyboard.press('Enter');`);
|
||||
return code.join("\n");
|
||||
}
|
||||
case "fill": {
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
const code = [`await page.${locator}.fill(${(0, import_stringUtils.escapeWithQuotes)(action.text)});`];
|
||||
if (action.submit)
|
||||
code.push(`await page.keyboard.press('Enter');`);
|
||||
return code.join("\n");
|
||||
}
|
||||
case "setChecked": {
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
if (action.checked)
|
||||
return `await page.${locator}.check();`;
|
||||
else
|
||||
return `await page.${locator}.uncheck();`;
|
||||
}
|
||||
case "expectVisible": {
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
const notInfix = action.isNot ? "not." : "";
|
||||
return `await expect(page.${locator}).${notInfix}toBeVisible();`;
|
||||
}
|
||||
case "expectValue": {
|
||||
const notInfix = action.isNot ? "not." : "";
|
||||
const locator = (0, import_locatorGenerators.asLocator)(sdkLanguage, action.selector);
|
||||
if (action.type === "checkbox" || action.type === "radio")
|
||||
return `await expect(page.${locator}).${notInfix}toBeChecked({ checked: ${action.value === "true"} });`;
|
||||
return `await expect(page.${locator}).${notInfix}toHaveValue(${(0, import_stringUtils.escapeWithQuotes)(action.value)});`;
|
||||
}
|
||||
case "expectAria": {
|
||||
const notInfix = action.isNot ? "not." : "";
|
||||
return `await expect(page.locator('body')).${notInfix}toMatchAria(\`
|
||||
${(0, import_stringUtils.escapeTemplateString)(action.template)}
|
||||
\`);`;
|
||||
}
|
||||
case "expectURL": {
|
||||
const arg = action.regex ? (0, import_stringUtils.parseRegex)(action.regex).toString() : (0, import_stringUtils.escapeWithQuotes)(action.value);
|
||||
const notInfix = action.isNot ? "not." : "";
|
||||
return `await expect(page).${notInfix}toHaveURL(${arg});`;
|
||||
}
|
||||
case "expectTitle": {
|
||||
const notInfix = action.isNot ? "not." : "";
|
||||
return `await expect(page).${notInfix}toHaveTitle(${(0, import_stringUtils.escapeWithQuotes)(action.value)});`;
|
||||
}
|
||||
}
|
||||
throw new Error("Unknown action " + action.method);
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
generateCode
|
||||
});
|
||||
150
node_modules/playwright-core/lib/server/agent/context.js
generated
vendored
Normal file
150
node_modules/playwright-core/lib/server/agent/context.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var context_exports = {};
|
||||
__export(context_exports, {
|
||||
Context: () => Context
|
||||
});
|
||||
module.exports = __toCommonJS(context_exports);
|
||||
var import_browserContext = require("../browserContext");
|
||||
var import_actionRunner = require("./actionRunner");
|
||||
var import_codegen = require("./codegen");
|
||||
var import_stringUtils = require("../../utils/isomorphic/stringUtils");
|
||||
class Context {
|
||||
constructor(page, agentParams, events) {
|
||||
this._actions = [];
|
||||
this._history = [];
|
||||
this.page = page;
|
||||
this.agentParams = agentParams;
|
||||
this.sdkLanguage = page.browserContext._browser.sdkLanguage();
|
||||
this.events = events;
|
||||
this._budget = { tokens: agentParams.maxTokens };
|
||||
}
|
||||
async runActionAndWait(progress, action) {
|
||||
return await this.runActionsAndWait(progress, [action]);
|
||||
}
|
||||
async runActionsAndWait(progress, action, options) {
|
||||
const error = await this.waitForCompletion(progress, async () => {
|
||||
for (const a of action) {
|
||||
await (0, import_actionRunner.runAction)(progress, "generate", this.page, a, this.agentParams?.secrets ?? []);
|
||||
const code = await (0, import_codegen.generateCode)(this.sdkLanguage, a);
|
||||
this._actions.push({ ...a, code });
|
||||
}
|
||||
return void 0;
|
||||
}, options).catch((error2) => error2);
|
||||
return await this.snapshotResult(progress, error);
|
||||
}
|
||||
async runActionNoWait(progress, action) {
|
||||
return await this.runActionsAndWait(progress, [action], { noWait: true });
|
||||
}
|
||||
actions() {
|
||||
return this._actions.slice();
|
||||
}
|
||||
history() {
|
||||
return this._history;
|
||||
}
|
||||
pushHistory(item) {
|
||||
this._history.push(item);
|
||||
this._actions = [];
|
||||
}
|
||||
consumeTokens(tokens) {
|
||||
if (this._budget.tokens === void 0)
|
||||
return;
|
||||
this._budget.tokens = Math.max(0, this._budget.tokens - tokens);
|
||||
}
|
||||
maxTokensRemaining() {
|
||||
return this._budget.tokens;
|
||||
}
|
||||
async waitForCompletion(progress, callback, options) {
|
||||
if (options?.noWait)
|
||||
return await callback();
|
||||
const requests = [];
|
||||
const requestListener = (request) => requests.push(request);
|
||||
const disposeListeners = () => {
|
||||
this.page.browserContext.off(import_browserContext.BrowserContext.Events.Request, requestListener);
|
||||
};
|
||||
this.page.browserContext.on(import_browserContext.BrowserContext.Events.Request, requestListener);
|
||||
let result;
|
||||
try {
|
||||
result = await callback();
|
||||
await progress.wait(500);
|
||||
} finally {
|
||||
disposeListeners();
|
||||
}
|
||||
const requestedNavigation = requests.some((request) => request.isNavigationRequest());
|
||||
if (requestedNavigation) {
|
||||
await this.page.mainFrame().waitForLoadState(progress, "load");
|
||||
return result;
|
||||
}
|
||||
const promises = [];
|
||||
for (const request of requests) {
|
||||
if (["document", "stylesheet", "script", "xhr", "fetch"].includes(request.resourceType()))
|
||||
promises.push(request.response().then((r) => r?.finished()));
|
||||
else
|
||||
promises.push(request.response());
|
||||
}
|
||||
await progress.race([...promises, progress.wait(5e3)]);
|
||||
if (!promises.length)
|
||||
await progress.wait(500);
|
||||
return result;
|
||||
}
|
||||
async takeSnapshot(progress) {
|
||||
const { full } = await this.page.snapshotForAI(progress, { doNotRenderActive: this.agentParams.doNotRenderActive });
|
||||
return full;
|
||||
}
|
||||
async snapshotResult(progress, error) {
|
||||
const snapshot = this._redactText(await this.takeSnapshot(progress));
|
||||
const text = [];
|
||||
if (error)
|
||||
text.push(`# Error
|
||||
${(0, import_stringUtils.stripAnsiEscapes)(error.message)}`);
|
||||
else
|
||||
text.push(`# Success`);
|
||||
text.push(`# Page snapshot
|
||||
${snapshot}`);
|
||||
return {
|
||||
isError: !!error,
|
||||
content: [{ type: "text", text: text.join("\n\n") }]
|
||||
};
|
||||
}
|
||||
async refSelectors(progress, params) {
|
||||
return Promise.all(params.map(async (param) => {
|
||||
try {
|
||||
const { resolvedSelector } = await this.page.mainFrame().resolveSelector(progress, `aria-ref=${param.ref}`);
|
||||
return resolvedSelector;
|
||||
} catch (e) {
|
||||
throw new Error(`Ref ${param.ref} not found in the current page snapshot. Try capturing new snapshot.`);
|
||||
}
|
||||
}));
|
||||
}
|
||||
_redactText(text) {
|
||||
const secrets = this.agentParams?.secrets;
|
||||
if (!secrets)
|
||||
return text;
|
||||
const redactText = (text2) => {
|
||||
for (const { name, value } of secrets)
|
||||
text2 = text2.replaceAll(value, `<secret>${name}</secret>`);
|
||||
return text2;
|
||||
};
|
||||
return redactText(text);
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
Context
|
||||
});
|
||||
156
node_modules/playwright-core/lib/server/agent/expectTools.js
generated
vendored
Normal file
156
node_modules/playwright-core/lib/server/agent/expectTools.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var expectTools_exports = {};
|
||||
__export(expectTools_exports, {
|
||||
default: () => expectTools_default
|
||||
});
|
||||
module.exports = __toCommonJS(expectTools_exports);
|
||||
var import_mcpBundle = require("../../mcpBundle");
|
||||
var import_locatorUtils = require("../../utils/isomorphic/locatorUtils");
|
||||
var import_yaml = require("../../utils/isomorphic/yaml");
|
||||
var import_tool = require("./tool");
|
||||
const expectVisible = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_expect_visible",
|
||||
title: "Expect element visible",
|
||||
description: "Expect element is visible on the page",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
role: import_mcpBundle.z.string().describe('ROLE of the element. Can be found in the snapshot like this: `- {ROLE} "Accessible Name":`'),
|
||||
accessibleName: import_mcpBundle.z.string().describe('ACCESSIBLE_NAME of the element. Can be found in the snapshot like this: `- role "{ACCESSIBLE_NAME}"`'),
|
||||
isNot: import_mcpBundle.z.boolean().optional().describe("Expect the opposite")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "expectVisible",
|
||||
selector: (0, import_locatorUtils.getByRoleSelector)(params.role, { name: params.accessibleName }),
|
||||
isNot: params.isNot
|
||||
});
|
||||
}
|
||||
});
|
||||
const expectVisibleText = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_expect_visible_text",
|
||||
title: "Expect text visible",
|
||||
description: `Expect text is visible on the page. Prefer ${expectVisible.schema.name} if possible.`,
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
text: import_mcpBundle.z.string().describe('TEXT to expect. Can be found in the snapshot like this: `- role "Accessible Name": {TEXT}` or like this: `- text: {TEXT}`'),
|
||||
isNot: import_mcpBundle.z.boolean().optional().describe("Expect the opposite")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "expectVisible",
|
||||
selector: (0, import_locatorUtils.getByTextSelector)(params.text),
|
||||
isNot: params.isNot
|
||||
});
|
||||
}
|
||||
});
|
||||
const expectValue = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_expect_value",
|
||||
title: "Expect value",
|
||||
description: "Expect element value",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the element"),
|
||||
element: import_mcpBundle.z.string().describe("Human-readable element description"),
|
||||
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot"),
|
||||
value: import_mcpBundle.z.string().describe('Value to expect. For checkbox, use "true" or "false".'),
|
||||
isNot: import_mcpBundle.z.boolean().optional().describe("Expect the opposite")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const [selector] = await context.refSelectors(progress, [{ ref: params.ref, element: params.element }]);
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "expectValue",
|
||||
selector,
|
||||
type: params.type,
|
||||
value: params.value,
|
||||
isNot: params.isNot
|
||||
});
|
||||
}
|
||||
});
|
||||
const expectList = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_expect_list_visible",
|
||||
title: "Expect list visible",
|
||||
description: "Expect list is visible on the page, ensures items are present in the element in the exact order",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
listRole: import_mcpBundle.z.string().describe("Aria role of the list element as in the snapshot"),
|
||||
listAccessibleName: import_mcpBundle.z.string().optional().describe("Accessible name of the list element as in the snapshot"),
|
||||
itemRole: import_mcpBundle.z.string().describe("Aria role of the list items as in the snapshot, should all be the same"),
|
||||
items: import_mcpBundle.z.array(import_mcpBundle.z.string().describe("Text to look for in the list item, can be either from accessible name of self / nested text content")),
|
||||
isNot: import_mcpBundle.z.boolean().optional().describe("Expect the opposite")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const template = `- ${params.listRole}:
|
||||
${params.items.map((item) => ` - ${params.itemRole}: ${(0, import_yaml.yamlEscapeValueIfNeeded)(item)}`).join("\n")}`;
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "expectAria",
|
||||
template
|
||||
});
|
||||
}
|
||||
});
|
||||
const expectURL = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_expect_url",
|
||||
title: "Expect URL",
|
||||
description: "Expect the page URL to match the expected value. Either provide a url string or a regex pattern.",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
url: import_mcpBundle.z.string().optional().describe("Expected URL string. Relative URLs are resolved against the baseURL."),
|
||||
regex: import_mcpBundle.z.string().optional().describe("Regular expression pattern to match the URL against, e.g. /foo.*/i."),
|
||||
isNot: import_mcpBundle.z.boolean().optional().describe("Expect the opposite")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "expectURL",
|
||||
value: params.url,
|
||||
regex: params.regex,
|
||||
isNot: params.isNot
|
||||
});
|
||||
}
|
||||
});
|
||||
const expectTitle = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_expect_title",
|
||||
title: "Expect title",
|
||||
description: "Expect the page title to match the expected value.",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
title: import_mcpBundle.z.string().describe("Expected page title."),
|
||||
isNot: import_mcpBundle.z.boolean().optional().describe("Expect the opposite")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "expectTitle",
|
||||
value: params.title,
|
||||
isNot: params.isNot
|
||||
});
|
||||
}
|
||||
});
|
||||
var expectTools_default = [
|
||||
expectVisible,
|
||||
expectVisibleText,
|
||||
expectValue,
|
||||
expectList,
|
||||
expectURL,
|
||||
expectTitle
|
||||
];
|
||||
204
node_modules/playwright-core/lib/server/agent/pageAgent.js
generated
vendored
Normal file
204
node_modules/playwright-core/lib/server/agent/pageAgent.js
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var pageAgent_exports = {};
|
||||
__export(pageAgent_exports, {
|
||||
pageAgentExpect: () => pageAgentExpect,
|
||||
pageAgentExtract: () => pageAgentExtract,
|
||||
pageAgentPerform: () => pageAgentPerform
|
||||
});
|
||||
module.exports = __toCommonJS(pageAgent_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_tool = require("./tool");
|
||||
var import_utilsBundle = require("../../utilsBundle");
|
||||
var import_mcpBundle = require("../../mcpBundle");
|
||||
var import_actionRunner = require("./actionRunner");
|
||||
var import_performTools = __toESM(require("./performTools"));
|
||||
var import_expectTools = __toESM(require("./expectTools"));
|
||||
var actions = __toESM(require("./actions"));
|
||||
async function pageAgentPerform(progress, context, userTask, callParams) {
|
||||
const cacheKey = (callParams.cacheKey ?? userTask).trim();
|
||||
if (await cachedPerform(progress, context, cacheKey))
|
||||
return;
|
||||
const task = `
|
||||
### Instructions
|
||||
- Perform the following task on the page.
|
||||
- Your reply should be a tool call that performs action the page".
|
||||
|
||||
### Task
|
||||
${userTask}
|
||||
`;
|
||||
progress.disableTimeout();
|
||||
await runLoop(progress, context, import_performTools.default, task, void 0, callParams);
|
||||
await updateCache(context, cacheKey);
|
||||
}
|
||||
async function pageAgentExpect(progress, context, expectation, callParams) {
|
||||
const cacheKey = (callParams.cacheKey ?? expectation).trim();
|
||||
if (await cachedPerform(progress, context, cacheKey))
|
||||
return;
|
||||
const task = `
|
||||
### Instructions
|
||||
- Call one of the "browser_expect_*" tools to verify / assert the condition.
|
||||
- You can call exactly one tool and it can't be report_results, must be one of the assertion tools.
|
||||
|
||||
### Expectation
|
||||
${expectation}
|
||||
`;
|
||||
progress.disableTimeout();
|
||||
await runLoop(progress, context, import_expectTools.default, task, void 0, callParams);
|
||||
await updateCache(context, cacheKey);
|
||||
}
|
||||
async function pageAgentExtract(progress, context, query, schema, callParams) {
|
||||
const task = `
|
||||
### Instructions
|
||||
Extract the following information from the page. Do not perform any actions, just extract the information.
|
||||
|
||||
### Query
|
||||
${query}`;
|
||||
const { result } = await runLoop(progress, context, [], task, schema, callParams);
|
||||
return result;
|
||||
}
|
||||
async function runLoop(progress, context, toolDefinitions, userTask, resultSchema, params) {
|
||||
if (!context.agentParams.api || !context.agentParams.model)
|
||||
throw new Error(`This action requires the API and API key to be set on the page agent. Did you mean to --run-agents=missing?`);
|
||||
if (!context.agentParams.apiKey)
|
||||
throw new Error(`This action requires API key to be set on the page agent.`);
|
||||
if (context.agentParams.apiEndpoint && !URL.canParse(context.agentParams.apiEndpoint))
|
||||
throw new Error(`Agent API endpoint "${context.agentParams.apiEndpoint}" is not a valid URL.`);
|
||||
const snapshot = await context.takeSnapshot(progress);
|
||||
const { tools, callTool, reportedResult, refusedToPerformReason } = (0, import_tool.toolsForLoop)(progress, context, toolDefinitions, { resultSchema, refuseToPerform: "allow" });
|
||||
const secrets = Object.fromEntries((context.agentParams.secrets || [])?.map((s) => [s.name, s.value]));
|
||||
const apiCacheTextBefore = context.agentParams.apiCacheFile ? await import_fs.default.promises.readFile(context.agentParams.apiCacheFile, "utf-8").catch(() => "{}") : "{}";
|
||||
const apiCacheBefore = JSON.parse(apiCacheTextBefore || "{}");
|
||||
const loop = new import_mcpBundle.Loop({
|
||||
api: context.agentParams.api,
|
||||
apiEndpoint: context.agentParams.apiEndpoint,
|
||||
apiKey: context.agentParams.apiKey,
|
||||
apiTimeout: context.agentParams.apiTimeout ?? 0,
|
||||
model: context.agentParams.model,
|
||||
maxTokens: params.maxTokens ?? context.maxTokensRemaining(),
|
||||
maxToolCalls: params.maxActions ?? context.agentParams.maxActions ?? 10,
|
||||
maxToolCallRetries: params.maxActionRetries ?? context.agentParams.maxActionRetries ?? 3,
|
||||
summarize: true,
|
||||
debug: import_utilsBundle.debug,
|
||||
callTool,
|
||||
tools,
|
||||
secrets,
|
||||
cache: apiCacheBefore,
|
||||
...context.events
|
||||
});
|
||||
const task = [];
|
||||
if (context.agentParams.systemPrompt) {
|
||||
task.push("### System");
|
||||
task.push(context.agentParams.systemPrompt);
|
||||
task.push("");
|
||||
}
|
||||
task.push("### Task");
|
||||
task.push(userTask);
|
||||
if (context.history().length) {
|
||||
task.push("### Context history");
|
||||
task.push(context.history().map((h) => `- ${h.type}: ${h.description}`).join("\n"));
|
||||
task.push("");
|
||||
}
|
||||
task.push("### Page snapshot");
|
||||
task.push(snapshot);
|
||||
task.push("");
|
||||
const { error, usage } = await loop.run(task.join("\n"), { signal: progress.signal });
|
||||
context.consumeTokens(usage.input + usage.output);
|
||||
if (context.agentParams.apiCacheFile) {
|
||||
const apiCacheAfter = { ...apiCacheBefore, ...loop.cache() };
|
||||
const sortedCache = Object.fromEntries(Object.entries(apiCacheAfter).sort(([a], [b]) => a.localeCompare(b)));
|
||||
const apiCacheTextAfter = JSON.stringify(sortedCache, void 0, 2);
|
||||
if (apiCacheTextAfter !== apiCacheTextBefore) {
|
||||
await import_fs.default.promises.mkdir(import_path.default.dirname(context.agentParams.apiCacheFile), { recursive: true });
|
||||
await import_fs.default.promises.writeFile(context.agentParams.apiCacheFile, apiCacheTextAfter);
|
||||
}
|
||||
}
|
||||
if (refusedToPerformReason())
|
||||
throw new Error(`Agent refused to perform action: ${refusedToPerformReason()}`);
|
||||
if (error)
|
||||
throw new Error(`Agentic loop failed: ${error}`);
|
||||
return { result: reportedResult ? reportedResult() : void 0 };
|
||||
}
|
||||
async function cachedPerform(progress, context, cacheKey) {
|
||||
if (!context.agentParams?.cacheFile)
|
||||
return;
|
||||
const cache = await cachedActions(context.agentParams?.cacheFile);
|
||||
const entry = cache.actions[cacheKey];
|
||||
if (!entry)
|
||||
return;
|
||||
for (const action of entry.actions)
|
||||
await (0, import_actionRunner.runAction)(progress, "run", context.page, action, context.agentParams.secrets ?? []);
|
||||
return entry.actions;
|
||||
}
|
||||
async function updateCache(context, cacheKey) {
|
||||
const cacheFile = context.agentParams?.cacheFile;
|
||||
const cacheOutFile = context.agentParams?.cacheOutFile;
|
||||
const cacheFileKey = cacheFile ?? cacheOutFile;
|
||||
const cache = cacheFileKey ? await cachedActions(cacheFileKey) : { actions: {}, newActions: {} };
|
||||
const newEntry = { actions: context.actions() };
|
||||
cache.actions[cacheKey] = newEntry;
|
||||
cache.newActions[cacheKey] = newEntry;
|
||||
if (cacheOutFile) {
|
||||
const entries = Object.entries(cache.newActions);
|
||||
entries.sort((e1, e2) => e1[0].localeCompare(e2[0]));
|
||||
await import_fs.default.promises.writeFile(cacheOutFile, JSON.stringify(Object.fromEntries(entries), void 0, 2));
|
||||
} else if (cacheFile) {
|
||||
const entries = Object.entries(cache.actions);
|
||||
entries.sort((e1, e2) => e1[0].localeCompare(e2[0]));
|
||||
await import_fs.default.promises.writeFile(cacheFile, JSON.stringify(Object.fromEntries(entries), void 0, 2));
|
||||
}
|
||||
}
|
||||
const allCaches = /* @__PURE__ */ new Map();
|
||||
async function cachedActions(cacheFile) {
|
||||
let cache = allCaches.get(cacheFile);
|
||||
if (!cache) {
|
||||
const content = await import_fs.default.promises.readFile(cacheFile, "utf-8").catch(() => "");
|
||||
let json;
|
||||
try {
|
||||
json = JSON.parse(content.trim() || "{}");
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse cache file ${cacheFile}:
|
||||
${error.message}`);
|
||||
}
|
||||
const parsed = actions.cachedActionsSchema.safeParse(json);
|
||||
if (parsed.error)
|
||||
throw new Error(`Failed to parse cache file ${cacheFile}:
|
||||
${import_mcpBundle.z.prettifyError(parsed.error)}`);
|
||||
cache = { actions: parsed.data, newActions: {} };
|
||||
allCaches.set(cacheFile, cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
pageAgentExpect,
|
||||
pageAgentExtract,
|
||||
pageAgentPerform
|
||||
});
|
||||
262
node_modules/playwright-core/lib/server/agent/performTools.js
generated
vendored
Normal file
262
node_modules/playwright-core/lib/server/agent/performTools.js
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var performTools_exports = {};
|
||||
__export(performTools_exports, {
|
||||
default: () => performTools_default
|
||||
});
|
||||
module.exports = __toCommonJS(performTools_exports);
|
||||
var import_mcpBundle = require("../../mcpBundle");
|
||||
var import_tool = require("./tool");
|
||||
const navigateSchema = import_mcpBundle.z.object({
|
||||
url: import_mcpBundle.z.string().describe("URL to navigate to")
|
||||
});
|
||||
const navigate = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_navigate",
|
||||
title: "Navigate to URL",
|
||||
description: "Navigate to a URL",
|
||||
inputSchema: navigateSchema
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
return await context.runActionNoWait(progress, {
|
||||
method: "navigate",
|
||||
url: params.url
|
||||
});
|
||||
}
|
||||
});
|
||||
const snapshot = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_snapshot",
|
||||
title: "Page snapshot",
|
||||
description: "Capture accessibility snapshot of the current page, this is better than screenshot",
|
||||
inputSchema: import_mcpBundle.z.object({})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
return await context.snapshotResult(progress);
|
||||
}
|
||||
});
|
||||
const elementSchema = import_mcpBundle.z.object({
|
||||
element: import_mcpBundle.z.string().describe("Human-readable element description used to obtain permission to interact with the element"),
|
||||
ref: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
|
||||
});
|
||||
const clickSchema = elementSchema.extend({
|
||||
doubleClick: import_mcpBundle.z.boolean().optional().describe("Whether to perform a double click instead of a single click"),
|
||||
button: import_mcpBundle.z.enum(["left", "right", "middle"]).optional().describe("Button to click, defaults to left"),
|
||||
modifiers: import_mcpBundle.z.array(import_mcpBundle.z.enum(["Alt", "Control", "ControlOrMeta", "Meta", "Shift"])).optional().describe("Modifier keys to press")
|
||||
});
|
||||
const click = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_click",
|
||||
title: "Click",
|
||||
description: "Perform click on a web page",
|
||||
inputSchema: clickSchema
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const [selector] = await context.refSelectors(progress, [params]);
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "click",
|
||||
selector,
|
||||
button: params.button,
|
||||
modifiers: params.modifiers,
|
||||
clickCount: params.doubleClick ? 2 : void 0
|
||||
});
|
||||
}
|
||||
});
|
||||
const drag = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_drag",
|
||||
title: "Drag mouse",
|
||||
description: "Perform drag and drop between two elements",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
startElement: import_mcpBundle.z.string().describe("Human-readable source element description used to obtain the permission to interact with the element"),
|
||||
startRef: import_mcpBundle.z.string().describe("Exact source element reference from the page snapshot"),
|
||||
endElement: import_mcpBundle.z.string().describe("Human-readable target element description used to obtain the permission to interact with the element"),
|
||||
endRef: import_mcpBundle.z.string().describe("Exact target element reference from the page snapshot")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const [sourceSelector, targetSelector] = await context.refSelectors(progress, [
|
||||
{ ref: params.startRef, element: params.startElement },
|
||||
{ ref: params.endRef, element: params.endElement }
|
||||
]);
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "drag",
|
||||
sourceSelector,
|
||||
targetSelector
|
||||
});
|
||||
}
|
||||
});
|
||||
const hoverSchema = elementSchema.extend({
|
||||
modifiers: import_mcpBundle.z.array(import_mcpBundle.z.enum(["Alt", "Control", "ControlOrMeta", "Meta", "Shift"])).optional().describe("Modifier keys to press")
|
||||
});
|
||||
const hover = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_hover",
|
||||
title: "Hover mouse",
|
||||
description: "Hover over element on page",
|
||||
inputSchema: hoverSchema
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const [selector] = await context.refSelectors(progress, [params]);
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "hover",
|
||||
selector,
|
||||
modifiers: params.modifiers
|
||||
});
|
||||
}
|
||||
});
|
||||
const selectOptionSchema = elementSchema.extend({
|
||||
values: import_mcpBundle.z.array(import_mcpBundle.z.string()).describe("Array of values to select in the dropdown. This can be a single value or multiple values.")
|
||||
});
|
||||
const selectOption = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_select_option",
|
||||
title: "Select option",
|
||||
description: "Select an option in a dropdown",
|
||||
inputSchema: selectOptionSchema
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const [selector] = await context.refSelectors(progress, [params]);
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "selectOption",
|
||||
selector,
|
||||
labels: params.values
|
||||
});
|
||||
}
|
||||
});
|
||||
const pressKey = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_press_key",
|
||||
title: "Press a key",
|
||||
description: "Press a key on the keyboard",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
key: import_mcpBundle.z.string().describe("Name of the key to press or a character to generate, such as `ArrowLeft` or `a`"),
|
||||
modifiers: import_mcpBundle.z.array(import_mcpBundle.z.enum(["Alt", "Control", "ControlOrMeta", "Meta", "Shift"])).optional().describe("Modifier keys to press")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "pressKey",
|
||||
key: params.modifiers ? [...params.modifiers, params.key].join("+") : params.key
|
||||
});
|
||||
}
|
||||
});
|
||||
const typeSchema = elementSchema.extend({
|
||||
text: import_mcpBundle.z.string().describe("Text to type into the element"),
|
||||
submit: import_mcpBundle.z.boolean().optional().describe("Whether to submit entered text (press Enter after)"),
|
||||
slowly: import_mcpBundle.z.boolean().optional().describe("Whether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.")
|
||||
});
|
||||
const type = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_type",
|
||||
title: "Type text",
|
||||
description: "Type text into editable element",
|
||||
inputSchema: typeSchema
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const [selector] = await context.refSelectors(progress, [params]);
|
||||
if (params.slowly) {
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "pressSequentially",
|
||||
selector,
|
||||
text: params.text,
|
||||
submit: params.submit
|
||||
});
|
||||
} else {
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "fill",
|
||||
selector,
|
||||
text: params.text,
|
||||
submit: params.submit
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
const fillForm = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_fill_form",
|
||||
title: "Fill form",
|
||||
description: "Fill multiple form fields. Always use this tool when you can fill more than one field at a time.",
|
||||
inputSchema: import_mcpBundle.z.object({
|
||||
fields: import_mcpBundle.z.array(import_mcpBundle.z.object({
|
||||
name: import_mcpBundle.z.string().describe("Human-readable field name"),
|
||||
type: import_mcpBundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the field"),
|
||||
ref: import_mcpBundle.z.string().describe("Exact target field reference from the page snapshot"),
|
||||
value: import_mcpBundle.z.string().describe("Value to fill in the field. If the field is a checkbox, the value should be `true` or `false`. If the field is a combobox, the value should be the text of the option.")
|
||||
})).describe("Fields to fill in")
|
||||
})
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const actions = [];
|
||||
for (const field of params.fields) {
|
||||
const [selector] = await context.refSelectors(progress, [{ ref: field.ref, element: field.name }]);
|
||||
if (field.type === "textbox" || field.type === "slider") {
|
||||
actions.push({
|
||||
method: "fill",
|
||||
selector,
|
||||
text: field.value
|
||||
});
|
||||
} else if (field.type === "checkbox" || field.type === "radio") {
|
||||
actions.push({
|
||||
method: "setChecked",
|
||||
selector,
|
||||
checked: field.value === "true"
|
||||
});
|
||||
} else if (field.type === "combobox") {
|
||||
actions.push({
|
||||
method: "selectOption",
|
||||
selector,
|
||||
labels: [field.value]
|
||||
});
|
||||
}
|
||||
}
|
||||
return await context.runActionsAndWait(progress, actions);
|
||||
}
|
||||
});
|
||||
const setCheckedSchema = elementSchema.extend({
|
||||
checked: import_mcpBundle.z.boolean().describe("Whether to check the checkbox")
|
||||
});
|
||||
const setChecked = (0, import_tool.defineTool)({
|
||||
schema: {
|
||||
name: "browser_set_checked",
|
||||
title: "Set checked",
|
||||
description: "Set the checked state of a checkbox",
|
||||
inputSchema: setCheckedSchema
|
||||
},
|
||||
handle: async (progress, context, params) => {
|
||||
const [selector] = await context.refSelectors(progress, [params]);
|
||||
return await context.runActionAndWait(progress, {
|
||||
method: "setChecked",
|
||||
selector,
|
||||
checked: params.checked
|
||||
});
|
||||
}
|
||||
});
|
||||
var performTools_default = [
|
||||
navigate,
|
||||
snapshot,
|
||||
click,
|
||||
drag,
|
||||
hover,
|
||||
selectOption,
|
||||
pressKey,
|
||||
type,
|
||||
fillForm,
|
||||
setChecked
|
||||
];
|
||||
109
node_modules/playwright-core/lib/server/agent/tool.js
generated
vendored
Normal file
109
node_modules/playwright-core/lib/server/agent/tool.js
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var tool_exports = {};
|
||||
__export(tool_exports, {
|
||||
defineTool: () => defineTool,
|
||||
toolsForLoop: () => toolsForLoop
|
||||
});
|
||||
module.exports = __toCommonJS(tool_exports);
|
||||
var import_mcpBundle = require("../../mcpBundle");
|
||||
var import_stringUtils = require("../../utils/isomorphic/stringUtils");
|
||||
function defineTool(tool) {
|
||||
return tool;
|
||||
}
|
||||
function toolsForLoop(progress, context, toolDefinitions, options = {}) {
|
||||
const tools = toolDefinitions.map((tool) => {
|
||||
const result = {
|
||||
name: tool.schema.name,
|
||||
description: tool.schema.description,
|
||||
inputSchema: import_mcpBundle.z.toJSONSchema(tool.schema.inputSchema)
|
||||
};
|
||||
return result;
|
||||
});
|
||||
if (options.resultSchema) {
|
||||
tools.push({
|
||||
name: "report_result",
|
||||
description: "Report the result of the task.",
|
||||
inputSchema: options.resultSchema
|
||||
});
|
||||
}
|
||||
if (options.refuseToPerform === "allow") {
|
||||
tools.push({
|
||||
name: "refuse_to_perform",
|
||||
description: "Refuse to perform action.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
reason: {
|
||||
type: "string",
|
||||
description: `Call this when you believe that you can't perform the action because something is wrong with the page. The reason will be reported to the user.`
|
||||
}
|
||||
},
|
||||
required: ["reason"]
|
||||
}
|
||||
});
|
||||
}
|
||||
let reportedResult;
|
||||
let refusedToPerformReason;
|
||||
const callTool = async (params) => {
|
||||
if (params.name === "report_result") {
|
||||
reportedResult = params.arguments;
|
||||
return {
|
||||
content: [{ type: "text", text: "Done" }],
|
||||
isError: false
|
||||
};
|
||||
}
|
||||
if (params.name === "refuse_to_perform") {
|
||||
refusedToPerformReason = params.arguments.reason;
|
||||
return {
|
||||
content: [{ type: "text", text: "Done" }],
|
||||
isError: false
|
||||
};
|
||||
}
|
||||
const tool = toolDefinitions.find((t) => t.schema.name === params.name);
|
||||
if (!tool) {
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Tool ${params.name} not found. Available tools: ${toolDefinitions.map((t) => t.schema.name)}`
|
||||
}],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
try {
|
||||
return await tool.handle(progress, context, params.arguments);
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{ type: "text", text: (0, import_stringUtils.stripAnsiEscapes)(error.message) }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
};
|
||||
return {
|
||||
tools,
|
||||
callTool,
|
||||
reportedResult: options.resultSchema ? () => reportedResult : void 0,
|
||||
refusedToPerformReason: () => refusedToPerformReason
|
||||
};
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
defineTool,
|
||||
toolsForLoop
|
||||
});
|
||||
Reference in New Issue
Block a user