UNPKG

donobu

Version:

Create browser automations with an LLM agent and replay them as Playwright scripts.

85 lines 4.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.installRecorder = installRecorder; const PageInteractionTracker_1 = require("../../../bindings/PageInteractionTracker"); const donobu_namespace_1 = require("../../../browser-side-scripts/donobu-namespace"); const page_interactions_tracker_1 = require("../../../browser-side-scripts/page-interactions-tracker"); const smart_selector_generator_1 = require("../../../browser-side-scripts/smart-selector-generator"); const Logger_1 = require("../../../utils/Logger"); const PlaywrightUtils_1 = require("../../../utils/PlaywrightUtils"); /** * Installs Donobu's standard interaction tracking infrastructure on the * page, using the same browser-side scripts (smart selectors, event * listeners) and server-side handling ({@link PageInteractionTracker}) * that the normal Donobu flow engine uses. * * This ensures: * - High-quality selectors (data-testid, aria-label, text, CSS, XPath) * - Proper keystroke merging (consecutive keys → inputText tool calls) * - No redundant navigation recording (only clicks/keydowns are tracked) * - Actions persist through the normal persistence layer (visible in UI) * - Post-action screenshots are captured automatically */ async function installRecorder(page, persistence, flowMetadata) { const invokedToolCalls = []; // Create a lightweight host with state locked to PAUSED so the tracker // records all events. Uses a shallow copy of metadata so we don't // mutate the original flow state. const tbdMetadata = { ...flowMetadata, state: 'PAUSED' }; const host = { metadata: tbdMetadata, invokedToolCalls, persistence, }; // Register the PageInteractionTracker binding on the browser context. // This also sets up addInitScript for namespace + smart selectors on // future navigations, and a framenavigated listener for new pages. await PageInteractionTracker_1.PageInteractionTracker.register(host, page.context()); // The register() call installs init scripts for future page loads, // but the current page needs the scripts evaluated manually. try { await page.evaluate(donobu_namespace_1.installDonobuNamespace); await page.evaluate(smart_selector_generator_1.installSmartSelectorGenerator); await page.evaluate(page_interactions_tracker_1.installPageInteractionsTracker); } catch { // May fail if the page is about:blank — the init scripts will // kick in on the next navigation. } // Re-install the interaction tracker after navigations on the current // page. The namespace and smart selector scripts are already handled // by addInitScript, but the tracker needs manual re-evaluation. page.on('framenavigated', async (frame) => { try { await frame.evaluate(page_interactions_tracker_1.installPageInteractionsTracker); } catch (error) { if (!PlaywrightUtils_1.PlaywrightUtils.isPageClosedError(error)) { Logger_1.appLogger.debug('tbd: failed to reinstall interaction tracker after navigation', error); } } }); let lastDrainIndex = 0; return { drainRecordedActions() { const newCalls = invokedToolCalls.slice(lastDrainIndex); lastDrainIndex = invokedToolCalls.length; return newCalls.map((tc) => { const parameters = { ...tc.parameters }; // When PageInteractionTracker merges consecutive keystrokes into // an inputText tool call, the selector lives in outcome.metadata // rather than in parameters. The codegen expects parameters.selector, // so backfill it from metadata when missing. if (!parameters.selector && tc.outcome?.metadata?.element) { parameters.selector = tc.outcome.metadata; } return { name: tc.toolName, parameters, toolCallId: tc.id, }; }); }, }; } //# sourceMappingURL=actionRecorder.js.map