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
| Option | Type | Default | Description |
|---|---|---|---|
schema | z.ZodObject | — | Zod schema for structured output. When provided, the return type is z.infer<Schema>. |
allowedTools | string[] | Default tool set | Restrict which tools the AI may use. See Available Tools Reference. |
maxToolCalls | number | 50 | Maximum number of tool invocations the AI may make before the flow is aborted. |
envVars | string[] | [] | Names of environment variables to expose to the AI for interpolation. See Environment Variable Interpolation. |
cache | boolean | true | Whether to use the cache. Set to false to always run autonomously. |
gptClient | GptClient | LanguageModel | Configured provider | Override the AI provider for this call. See AI Provider Configuration. |
volatileElementIds | boolean | false | When true, AI-generated selectors that rely solely on an id attribute are treated as unstable and deprioritised when writing to the cache. |
noSelectorFailover | boolean | false | When 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: returnsPromise<void> - With
schema: returnsPromise<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:
| Property | Type | Description |
|---|---|---|
originalInstruction | string | The instruction that was passed to page.ai() |
metadata.state | string | The terminal state (e.g. 'FAILED', 'NOT_COMPLETABLE') |
metadata.result | unknown | Any 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.
Related
page.ai.assert— assert a condition without a full flowpage.ai.extract— extract structured data without a full flow- Available Tools Reference
- Environment Variable Interpolation