recoveryAction lets a workflow recover from a supported Playwright Page or Locator failure. When a supported action fails, Libretto runs the recovery action and retries the original action once.12345678910export default workflow("reviewOrder", { input, output, recoveryAction, handler: async ({ page }, params) => { await page.goto(params.url); await page.locator("#review").click(); return { complete: true }; }, });
computerUseRecoveryAction() runs a small vision agent with your instruction. It screenshots the viewport, asks the model for a browser action, executes it with Playwright coordinates, and stops when the model returns done or maxSteps is reached.maxSteps is 3, which covers the common popup flow of close, confirm, then done.123456789import { computerUseRecoveryAction } from "libretto"; const recoveryAction = computerUseRecoveryAction({ provider: "openai", apiKey: process.env.OPENAI_API_KEY!, model: "gpt-5.5", instruction: "Close any visible blocker that prevents submitting the form.", maxSteps: 3, });
12{ provider: "openai", apiKey, model?: "gpt-5.5" } { provider: "anthropic", apiKey, model?: "claude-sonnet-4-6" }
LanguageModel with languageModel.popupRecoveryAction() is a preset for the common popup case. It uses Libretto's default instruction for closing popups, cookie banners, modals, overlays, and similar blockers.12345678import { popupRecoveryAction } from "libretto"; const recoveryAction = popupRecoveryAction({ provider: "anthropic", apiKey: process.env.ANTHROPIC_API_KEY!, model: "claude-sonnet-4-6", maxSteps: 3, });
RecoveryAction when the site needs deterministic recovery logic, or when it needs to combine popupRecoveryAction() with other steps such as reloading the page.123456789101112131415161718import { popupRecoveryAction, type RecoveryAction, } from "libretto"; const popupRecoveryAgent = popupRecoveryAction({ provider: "openai", apiKey: process.env.OPENAI_API_KEY!, model: "gpt-5.5", }); const recoveryAction: RecoveryAction = async (context) => { const result = await popupRecoveryAgent(context); if (result.status === "incomplete") { await context.page.reload(); } return result; };