UNPKG

cucumber-ai

Version:

Write automated tests using natural language

336 lines 13.4 kB
"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