cucumber-ai
Version:
Write automated tests using natural language
336 lines • 13.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserAgent = void 0;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = require("node:path");
class BrowserAgent {
constructor(context) {
this.tools = [];
this.toolMap = {};
this.context = context;
this.started = false;
}
async start() {
if (this.started) {
await this.stop();
}
this.systemPrompt = node_fs_1.default.readFileSync((0, node_path_1.join)(__dirname, "system.prompt.md"), "utf-8");
this.setupTools();
this.registerActions(this.context.getActions());
this.started = true;
}
setupTools() {
const toolDefinitions = [
{
name: "open",
description: "Open the specified URL",
parameters: {
type: "object",
properties: {
url: {
type: "string",
description: "URL to open",
},
},
required: ["url"],
},
},
{
name: "saveScreenshot",
description: "Save a screenshot of the current page",
parameters: {
type: "object",
properties: {
name: {
type: "string",
description: "Screenshot filename (without extension)",
},
},
required: ["name"],
},
},
{
name: "saveVideo",
description: "Save the recorded video",
parameters: {
type: "object",
properties: {
name: {
type: "string",
description: "Video filename (without extension)",
},
},
required: ["name"],
},
},
{
name: "deleteVideo",
description: "Delete the recorded video",
parameters: {
type: "object",
properties: {},
},
},
{
name: "addItemInLocalStorage",
description: "Add an item to local storage",
parameters: {
type: "object",
properties: {
key: {
type: "string",
description: "Storage key",
},
value: {
type: "string",
description: "Storage value",
},
},
required: ["key", "value"],
},
},
{
name: "quit",
description: "Close the browser",
parameters: {
type: "object",
properties: {},
},
},
{
name: "ai",
description: "Perform general AI-powered action on the page for request without specific location or context or no other tool could match the request",
parameters: {
type: "object",
properties: {
prompt: {
type: "string",
description: "Natural language description of the action to perform",
},
type: {
type: "string",
description: "Optional action type",
},
},
required: ["prompt"],
},
},
{
name: "aiTap",
description: "Click on an element using AI to locate it",
parameters: {
type: "object",
properties: {
locatePrompt: {
type: "string",
description: "Natural language description of the element to click",
},
},
required: ["locatePrompt"],
},
},
{
name: "aiInput",
description: "Type text into an input field using AI to locate it",
parameters: {
type: "object",
properties: {
value: {
type: "string",
description: "Text to type",
},
locatePrompt: {
type: "string",
description: "Natural language description of the input field",
},
},
required: ["value", "locatePrompt"],
},
},
{
name: "aiHover",
description: "Hover over an element using AI to locate it",
parameters: {
type: "object",
properties: {
locatePrompt: {
type: "string",
description: "Natural language description of the element to hover over",
},
},
required: ["locatePrompt"],
},
},
{
name: "aiKeyboardPress",
description: "Press keyboard keys, optionally on a specific element",
parameters: {
type: "object",
properties: {
key: {
type: "string",
description: "Key or key combination to press (e.g., 'Enter', 'Ctrl+A')",
},
locatePrompt: {
type: "string",
description: "Optional natural language description of the element to focus before pressing keys",
},
},
required: ["key"],
},
},
{
name: "aiWaitFor",
description: "Wait for a condition to be met on the page",
parameters: {
type: "object",
properties: {
prompt: {
type: "string",
description: "Natural language description of the condition to wait for",
},
timeoutMs: {
type: "number",
description: "Timeout in milliseconds (default: 30000)",
},
},
required: ["prompt"],
},
},
{
name: "aiAssert",
description: "Assert that a condition is true on the page",
parameters: {
type: "object",
properties: {
assertion: {
type: "string",
description: "Natural language description of what should be true",
},
message: {
type: "string",
description: "Optional custom error message if assertion fails",
},
},
required: ["assertion"],
},
},
];
this.toolMap = {
open: async (args) => {
const url = args.url;
await this.context.getDriver().open(url);
return { action: "open", details: `Successfully opened URL: ${url}` };
},
saveScreenshot: async (args) => {
const name = args.name;
await this.context.getDriver().saveScreenshot(name);
return { action: "saveScreenshot", details: `Screenshot saved as: ${name}.png` };
},
saveVideo: async (args) => {
const name = args.name;
await this.context.getDriver().saveVideo(name);
return { action: "saveVideo", details: `Video saved as: ${name}.webm` };
},
deleteVideo: async () => {
await this.context.getDriver().deleteVideo();
return { action: "deleteVideo", details: "Video deleted" };
},
addItemInLocalStorage: async (args) => {
const key = args.key;
const value = args.value;
await this.context.getDriver().addItemInLocalStorage(key, value);
return { action: "addItemInLocalStorage", details: `Added local storage item: ${key} = ${value}` };
},
quit: async () => {
await this.context.getDriver().quit();
return { action: "quit", details: "Browser closed" };
},
ai: async (args) => {
const prompt = args.prompt;
const type = args.type;
await this.context.getUIAgent().ai(prompt, type);
return { action: "ai", details: `AI action completed: ${prompt}` };
},
aiTap: async (args) => {
const locatePrompt = args.locatePrompt;
await this.context.getUIAgent().aiTap(locatePrompt);
return { action: "aiTap", details: `Clicked on: ${locatePrompt}` };
},
aiInput: async (args) => {
const value = args.value;
const locatePrompt = args.locatePrompt;
await this.context.getUIAgent().aiInput(value, locatePrompt);
return { action: "aiInput", details: `Typed "${value}" into: ${locatePrompt}` };
},
aiHover: async (args) => {
const locatePrompt = args.locatePrompt;
await this.context.getUIAgent().aiHover(locatePrompt);
return { action: "aiHover", details: `Hovered over: ${locatePrompt}` };
},
aiKeyboardPress: async (args) => {
const key = args.key;
const locatePrompt = args.locatePrompt;
await this.context.getUIAgent().aiKeyboardPress(key, locatePrompt);
return { action: "aiKeyboardPress", details: `Pressed "${key}"${locatePrompt ? ` on: ${locatePrompt}` : ""}` };
},
aiWaitFor: async (args) => {
const prompt = args.prompt;
const timeoutMs = args.timeoutMs || 30000;
await this.context.getUIAgent().aiWaitFor(prompt, { timeoutMs });
return { action: "aiWaitFor", details: `Waited for condition: ${prompt}` };
},
aiAssert: async (args) => {
const assertion = args.assertion;
const message = args.message;
await this.context.getUIAgent().aiAssert(assertion, message);
return { action: "aiAssert", details: `Assertion verified: ${assertion}` };
},
};
this.tools = toolDefinitions.map((tool) => ({
type: "function",
function: {
name: tool.name,
description: tool.description,
parameters: tool.parameters,
},
}));
}
async stop() {
if (this.started) {
try {
await this.context.getDriver().quit();
}
catch (error) {
console.warn("Error closing browser:", error);
}
this.unregisterActions(this.context.getActions());
this.started = false;
}
}
async ask(prompt, opts = {}) {
const callTool = async (toolCall) => {
const toolName = toolCall.function.name;
const args = JSON.parse(toolCall.function.arguments);
return JSON.stringify(await this.toolMap[toolName](args));
};
return await this.context.getToolExecutor().execute(prompt, {
callTool,
useCache: opts.useCache ?? this.context.isCacheEnabled(),
systemPrompt: this.systemPrompt,
cacheKey: "browser-agent",
tools: this.tools,
});
}
registerActions(actions) {
actions.register("browser", async (text) => await this.ask(text));
}
unregisterActions(actions) {
actions.unregister("browser");
}
}
exports.BrowserAgent = BrowserAgent;
//# sourceMappingURL=index.js.map