Skip to main content
Every agent call is one bounded invocation: a fresh observation, an explicit deadline, a model-call budget, and no shared transcript between calls. Acquiring the fixture without a configured model fails with MODEL_UNAVAILABLE.

Budgets

Model calls count every model request including repair rounds. Action steps count committed engine actions. Every timeout is additionally capped by the remaining test timeout. The judgment budget is max(30000, config.actionTimeout) milliseconds. Per-call budgets must be positive integers and can only lower the configured limits. Every duration option is milliseconds. The assert row holds for the built-in agent. When the selected agent has a custom executor, assert is dispatched to it as a step: its budget is the agent’s maxSteps and maxModelCalls, its default timeout is config.timeout, and vision or screenshot on the call is UNSUPPORTED_CAPABILITY.

agent.act

Plans and executes one bounded multi-action flow. A passing verdict resolves with an ActResult; a failing or blocked one throws an AgentError whose code and blocked flag say why. Values come from your code through options.params, never from the model. A Secret in params is projected before the model sees anything: the model receives the secret’s name and purpose, and the harness fills the value host-side under the same authorization as locator.fill: the credential must be registered, the current origin allowed by both the target and the credential, and the field an enabled secure input whose purpose matches.
The result carries the step’s summary, the modelCalls and actions it spent, and cache: how the trace cache took part (self-finalized, agent-concluded, or missed with a reason; absent when caching is off).

Pixel tools: screenshot and tap_at

act takes no vision option. Pixels reach an act step through two tools the built-in agent offers while pixels can leave the runner. The act model itself receives the image: no separate vision model, no extra model call, and nothing lost in a description. While the step is showing pixels, the wait after an action watches the pixels too: a tap that redraws a canvas is read as soon as the redraw lands, instead of waiting out the change window on a tree that never moves. A screen that lists nothing to act on by id (a canvas, a game, a semantics-free native screen) opens with a screenshot already attached, so the model never spends a turn discovering that it needs one; any screen with a listed control opens tree-only and the model asks when the tree falls short. Older screenshots are elided from the conversation in batches, keeping the newest two, so a long flow in pixel mode carries a bounded number of images, and each is resampled to a long side of at most 768 pixels before it goes to the model: on a drawn keypad and a drawn wizard that size kept every run passing at a third less cost than the full capture, and 512 did not. Coordinates the model returns are in that image; the harness scales them back. Both tools are offered while no secret has been filled when the step opens; a secret filled during the step keeps them listed but withholds every later screenshot (PIXEL_TAINTED), and each result says so; tap_at needs an engine that can tap by node (perform) or by point (tapAt, the pointer capability, which the Playwright and agent-device engines declare), and on an engine without tapAt the point must land on a listed control. A bare-point tap replays from the trace cache the way a coordinate-driven tool does: the same point on a viewport of the recorded size, or, when a listed node contained the point, the same place inside that node’s live box. A viewport of another size or a node that cannot be re-found hands the step to the model, and the recorded end state still has to return before a replay passes on its own. A step that sent pixels records visionInput: true and metrics.pixelBytes. The pixel path asks the act model to ground a point in an image, and models differ widely there. Measured on a drawn ten-key keypad and an eight-screen drawn wizard: the gpt-5.6 luna family and Gemini 3.8 Flash completed both; Claude Sonnet 5 completed the wizard’s large shapes but never the keypad’s small keys; DeepSeek and GLM flash models gave up, and their providers bill a 1280 by 720 screenshot at tens of thousands of input tokens against a few hundred on OpenAI. Pin an act model that grounds well when your flows leave the tree. Throws ACTION_FAILED for a failed verdict with no more specific code; a blocked code (AUTH_CREDENTIAL_UNAVAILABLE, ENVIRONMENT_UNAVAILABLE, SEED_DATA_MISSING, TEST_SETUP_FAILED, AUTOMATION_UNSUPPORTED) when the step could not reach a product verdict; STEP_BUDGET_EXHAUSTED and STEP_TIMEOUT when a budget or the deadline ran out; INVALID_ARGUMENT for a malformed instruction, oversized params, or an unknown option; and UNSUPPORTED_CAPABILITY for schema or vision, which act does not take.

agent.assert

One fresh observation, exactly one judgment. It does not poll. Throws ASSERTION_FAILED on a false judgment, carrying the explanation and, when permitted, a screenshot path. Evidence is skipped with screenshot: false and once any secret has been filled in the attempt. screenshot controls failure evidence attached after the judgment; vision controls what the model is shown before it.

agent.waitFor

One observation per interval, and a judgment when the screen changed. Succeeds on the first true judgment. Throws STEP_TIMEOUT on deadline expiry and STEP_BUDGET_EXHAUSTED on budget exhaustion, each carrying the last judgment, and INVALID_ARGUMENT for an out-of-range option or one waitFor does not take.

agent.extract

Takes one fresh observation, requests structured output, validates it, and returns the validated value. It performs no app actions. The budget is two model calls: one extraction and one repair round for output that failed validation. Throws INVALID_ARGUMENT for a schema that is not Standard Schema v1, and MODEL_OUTPUT_INVALID when validation still fails after the repair.

Vision

assert, waitFor, and extract accept vision. It controls what evidence the model is shown. Sending pixels needs a model that accepts images; images are billed as input tokens. act has no such option; its pixel path is the screenshot and tap_at tools above. Set vision on the agent in config to make a mode the project default; a per-call value wins. Pixels go to the agent’s model, the same one the act loop shows its screenshots to.
Use 'only' for questions about what the page presentsvision: true sends the tree and the screenshot, and the tree is a cheaper path to an answer. A consent sheet covering a form, a price at opacity: 0, a button under a cookie banner: the tree reports all of them as fine.
Use true when the tree is part of the answer, such as a disabled state that is not visible at all.
The screenshot is the viewport, never the full page, so 'only' cannot see below the fold. Write 'only' conditions about what is on screen and let the flow scroll first. Pixel evidence degrades instead of failing the call in every mode but 'only'. It is withheld, and the tree sent alone, when a secret fill has tainted the viewport (visionDegraded: "PIXEL_TAINTED" on the step), when the engine masked fewer regions than the secure fields it observed (MASKING_UNPROVEN), or when the engine cannot capture pixels (UNSUPPORTED_CAPABILITY). 'only' fails with POLICY_DENIED in those cases rather than answer a question about pixels from the tree. A step that sent pixels records visionInput: true and metrics.pixelBytes.

Types

AgentError

Check code with isAgentError(error), exported from @e2edev/e2e, rather than instanceof, which does not hold across the runner’s module realms. Every code, its class, and its exit code are in Errors.

Usage accounting

Model usage is accounted per step and per run. A step reports tokenAccounting: 'provider' only when every call supplied complete provider token counts; otherwise the aggregate stays at adapter-upper-bound. Reported costs accumulate where the provider gives one. Token sums saturate at Number.MAX_SAFE_INTEGER and an overflowing cost total is omitted.

How agent steps work

Agents and personas

Config

Errors