page.ai() — Autonomous AI Flow

The primary Donobu API for launching autonomous AI flows that navigate and interact with the browser to accomplish plain-English instructions.

page.ai is the primary API in Donobu. Calling it launches an autonomous flow where the AI navigates and interacts with the browser to accomplish a plain-English instruction.

Signature

await page.ai(
  instruction: string,
  options?: {
    schema?: z.ZodObject;         // Zod schema for structured output
    allowedTools?: string[];      // Restrict which tools the AI may use
    maxToolCalls?: number;        // Cap on tool invocations (default: 50)
    envVars?: string[];           // Environment variable names to expose to the AI
    cache?: boolean;              // Use the cache (default: true)
    gptClient?: GptClient | LanguageModel; // Override the AI provider for this call
    volatileElementIds?: boolean; // Treat id-only selectors as unstable (default: false)
    noSelectorFailover?: boolean; // Disable fallback selectors in the cache (default: false)
  }
): Promise<void | z.infer<Schema>>

Basic usage

import { test } from 'donobu';

test('dismiss cookie banner and log in', async ({ page }) => {
  await page.goto('https://app.example.com');
  await page.ai('Dismiss any cookie banner, then log in with the test account');
});

Returning structured data

Pass a Zod schema as the schema option to receive typed output:

import { test } from 'donobu';
import { z } from 'zod';

test('read user profile', async ({ page }) => {
  await page.goto('https://app.example.com/profile');

  const profile = await page.ai('Open the user profile and read the details', {
    schema: z.object({
      fullName: z.string(),
      email: z.string().email(),
      plan: z.string(),
    }),
  });

  expect(profile.plan).toBe('Pro');
});

Options

OptionTypeDefaultDescription
schemaz.ZodObjectZod schema for structured output. When provided, the return type is z.infer<Schema>.
allowedToolsstring[]Default tool setRestrict which tools the AI may use. See Available Tools Reference.
maxToolCallsnumber50Maximum number of tool invocations the AI may make before the flow is aborted.
envVarsstring[][]Names of environment variables to expose to the AI for interpolation. See Environment Variable Interpolation.
cachebooleantrueWhether to use the cache. Set to false to always run autonomously.
gptClientGptClient | LanguageModelConfigured providerOverride the AI provider for this call. See AI Provider Configuration.
volatileElementIdsbooleanfalseWhen true, AI-generated selectors that rely solely on an id attribute are treated as unstable and deprioritised when writing to the cache.
noSelectorFailoverbooleanfalseWhen true, only the primary AI-generated selector is stored in the cache — no fallback selectors are saved. See page.find for more on how Donobu generates and uses selectors.

allowedTools example

Narrowing the tool set improves reliability for flows where you know exactly what kind of interactions are needed:

await page.ai('Fill in and submit the sign-up form', {
  allowedTools: ['click', 'inputText', 'chooseSelectOption', 'pressKey'],
});

envVars and interpolation

Use Donobu's {{$.env.VAR_NAME}} interpolation syntax instead of JavaScript template literals when the value changes between environments. This keeps the cache key stable:

// ✅ Correct — cache key stays constant across environments
await page.ai(
  'Log in as {{$.env.TEST_USERNAME}} with password {{$.env.TEST_PASSWORD}}',
  {
    envVars: ['TEST_USERNAME', 'TEST_PASSWORD'],
  },
);

// ❌ Avoid — JS interpolation bakes the value into the cache key
await page.ai(
  `Log in as ${process.env.TEST_USERNAME} with password ${process.env.TEST_PASSWORD}`,
);

See Environment Variable Interpolation for full details.

Return value

  • Without schema: returns Promise<void>
  • With schema: returns Promise<z.infer<Schema>>

Error handling

page.ai() throws PageAiException when the autonomous flow ends in a non-success state — for example, if the AI cannot find a way to complete the instruction or hits the maxToolCalls limit.

import { PageAiException } from 'donobu';

try {
  await page.ai('Complete the checkout');
} catch (e) {
  if (e instanceof PageAiException) {
    console.log('Flow failed in state:', e.metadata.state);
    console.log('Original instruction:', e.originalInstruction);
  }
}

PageAiException properties:

PropertyTypeDescription
originalInstructionstringThe instruction that was passed to page.ai()
metadata.statestringThe terminal state (e.g. 'FAILED', 'NOT_COMPLETABLE')
metadata.resultunknownAny partial result payload, if the AI produced one before failing

Caching behaviour

On the first run, the AI executes the flow and the resulting action sequence is written to .cache-lock/<test-file>.cache.js. On subsequent runs, Donobu replays the cached sequence without calling the AI.

Set cache: false on a call to skip cache lookup and always run autonomously. To invalidate all cache entries for an entire run, pass --clear-ai-cache to npx donobu test or set the DONOBU_PAGE_AI_CLEAR_CACHE=1 environment variable.

See Caching System for full details.