@revyl/verify 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -3
- package/README.md +12 -12
- package/dist/api/client.js +21 -2
- package/dist/cli/init.js +11 -8
- package/dist/cli/main.js +1 -1
- package/dist/computer-session.js +1 -1
- package/docs/agents.md +3 -3
- package/docs/api.md +7 -7
- package/docs/ci.md +2 -2
- package/docs/computers.md +3 -3
- package/docs/configuration.md +4 -4
- package/docs/end-to-end.md +2 -0
- package/docs/errors.md +2 -2
- package/docs/getting-started.md +1 -1
- package/docs/llms.txt +2 -2
- package/docs/mobile.md +11 -11
- package/docs/own-model.md +4 -4
- package/docs/web.md +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.6.
|
|
3
|
+
## 0.6.1 (unreleased)
|
|
4
|
+
|
|
5
|
+
- An iOS or Android `open()` that Revyl refuses as invalid (HTTP 400 or 422) throws `INVALID_ARGUMENT` with Revyl's explanation instead of a bare `API_ERROR … failed with HTTP 422`. For a device model or OS version Revyl doesn't offer, the message lists the values it accepts, as in `Revyl refused to start the session (HTTP 422): Unsupported ios runtime '18.5'. Available: ['iOS 27.1', …, 'iOS 18.5']. Change the target to a value Revyl accepts and run again.` No session was started. Web and hosted starts keep their safe diagnostic codes and copy no server text.
|
|
6
|
+
- `device.osVersion` is the name Revyl uses, such as `'iOS 18.5'` or `'Android 14'`, as before; Verify sends it unchanged. The docs now show it that way, with models Revyl offers (`iPhone 16`, `iPhone Air`, `Pixel 7`).
|
|
7
|
+
- `verify init --platform web --url <url>` with a URL other than `https://example.com` writes an example with one validation that passes on any page that loads, instead of example.com's steps.
|
|
8
|
+
- Mac computer messages say what Revyl checks: a current paid plan. `init --platform mac` prints that instead of "early access", and computer errors say `Mac computers need a current paid Revyl plan, and Linux computers are not generally available.`
|
|
9
|
+
- Every other call sends the same requests as 0.6.0.
|
|
10
|
+
- Docs: device selectors Revyl accepts, a mobile exact-actions script that searches Settings for Accessibility, a web exact-actions script that scrolls back up before it locates the cart, `node verify/checkout.mts` in CI, non-owning attach examples that navigate to a public page, Mac availability on paid plans, `init --platform` in the README, your own model's Claude results, and `end-to-end.md` marked as a record of the 0.1.0 and 0.2.0 runs.
|
|
11
|
+
|
|
12
|
+
## Go 0.5.1 (unreleased)
|
|
13
|
+
|
|
14
|
+
Published as the `go/v0.5.1` tag.
|
|
15
|
+
|
|
16
|
+
- `ErrValidationFailed` names the step and the reason, as TypeScript does: `Validation failed: "<text>". <reason> See <link>`.
|
|
17
|
+
- An iOS or Android `Open` that Revyl refuses as invalid (HTTP 400 or 422) returns `ErrInvalidArgument` with Revyl's explanation, as in TypeScript 0.6.1, including the device models or OS versions it accepts. No session was started.
|
|
18
|
+
- The computer availability message says Mac computers need a current paid Revyl plan. Every other call sends the same requests as v0.5.0.
|
|
19
|
+
|
|
20
|
+
## Python 0.4.1 (unreleased)
|
|
21
|
+
|
|
22
|
+
- `VALIDATION_FAILED` names the step and the reason, as TypeScript does: `Validation failed: "<text>". <reason> See <link>`. `AsyncSession` gets the same message.
|
|
23
|
+
- An iOS or Android `open()` that Revyl refuses as invalid (HTTP 400 or 422) raises `INVALID_ARGUMENT` with Revyl's explanation, as in TypeScript 0.6.1, including the device models or OS versions it accepts. No session was started.
|
|
24
|
+
- The computer availability message says Mac computers need a current paid Revyl plan. Every other call sends the same requests as 0.4.0.
|
|
25
|
+
- Docs: device selectors Revyl accepts, `open_url("https://example.com")` in the exact-actions example, and a non-owning attach example.
|
|
26
|
+
|
|
27
|
+
## 0.6.0 (2026-11-12)
|
|
4
28
|
|
|
5
29
|
- Early access: a Mac computer's screen. `tap({ x, y })` clicks a point in screenshot pixels and resolves with it, `screenSize()` returns the screenshot's size, `typeFocused(text, { clear: false })` types where the cursor is, and `pressKey(key, { modifiers })` takes the Web keys and modifiers, where `'meta'` is Command and `'alt'` is Option, as in `pressKey('a', { modifiers: ['meta'] })` to select all.
|
|
6
30
|
- `typeFocused` on a computer requires `{ clear: false }` and throws `INVALID_ARGUMENT` without it, naming the fix. It takes up to 16,384 characters, with line breaks and tabs; other control characters are refused before anything is sent. Text over 500 characters goes in pieces, in order, and a failure part way says how many characters were certainly typed and whether the failed piece may have been.
|
|
@@ -12,7 +36,7 @@
|
|
|
12
36
|
- Error messages on a computer say what happened and what to do next. `screen_control_lost` on a screen action throws `SESSION_BUSY` saying nothing was sent and to try again. `owner_unavailable`, a 5xx or no answer on a screen action throws `ACTION_UNCERTAIN` saying to take a screenshot before repeating it. `invalid_request` on `tap({ x, y })` says nothing was clicked and to pick the point from a new screenshot, and `screen_key_unsupported` says nothing was pressed. Partial typing counts characters as Unicode code points, the same in TypeScript, Python and Go, and a failure in the first piece says nothing was certainly typed. Every other computer refusal adds a next step, and the `screen_starting` message says "1 second" rather than "1 seconds".
|
|
13
37
|
- Docs: a Screen section in `computers.md`, the platform table, `api.md`, `errors.md`, `agents.md` and `llms.txt`. The Web docs say `'meta'` is not the shortcut key there; use `'ctrl'`.
|
|
14
38
|
|
|
15
|
-
## Go 0.5.0 (
|
|
39
|
+
## Go 0.5.0 (2026-11-12)
|
|
16
40
|
|
|
17
41
|
Published as the `go/v0.5.0` tag.
|
|
18
42
|
|
|
@@ -20,7 +44,7 @@ Published as the `go/v0.5.0` tag.
|
|
|
20
44
|
- The same limits, errors and refusals as TypeScript 0.6.0: `ErrSessionBusy` for `screen_control_held`, `ErrActionUncertain` for an action Revyl can't confirm, `ErrAuthRejected` for a 403, `ErrActionFailed` for `screen_target_not_found`, a wait of up to 30 seconds on `screen_starting`, and `ErrNotAvailableOnPlatform` before any request for `Locate` and the other exact actions. Every other call sends the same requests as v0.4.0.
|
|
21
45
|
- The same error messages as TypeScript 0.6.0, each with a next step, with partial typing counted in Unicode code points.
|
|
22
46
|
|
|
23
|
-
## Python 0.4.0 (
|
|
47
|
+
## Python 0.4.0 (2026-11-12)
|
|
24
48
|
|
|
25
49
|
- Early access: a Mac computer's screen, as in TypeScript 0.6.0. `tap(Point(x, y))`, `tap("description")` returning the point it clicked, `screen_size()`, `type_focused(text, clear=False)` and `press_key(key, modifiers=[...])`, where `"meta"` is Command. Leaving `clear` out raises `INVALID_ARGUMENT` naming the fix. `AsyncSession` has the same methods.
|
|
26
50
|
- The same limits, errors and refusals as TypeScript 0.6.0, and every other call sends the same requests as 0.3.0.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Verify
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
Verify runs end-to-end checks in a cloud browser, iOS simulator, or Android emulator on Revyl. You write what the agent should do and what must be true afterward, in plain sentences, and call it from a script, a coding agent, CI, or the test runner you already use. When you know exactly what to press, you can tap, type and swipe yourself instead. Verify also opens Mac computers for commands, files, screenshots, and clicks and keys on the screen.
|
|
6
6
|
|
|
@@ -38,12 +38,12 @@ Ask me before anything that needs my login or approval.
|
|
|
38
38
|
Or set it up yourself:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
npx @revyl/verify init
|
|
41
|
+
npx @revyl/verify init --platform ios
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
`init` adds Verify to your project,
|
|
44
|
+
`init` adds Verify to your project, writes `verify.config.ts` and an example script for the platform you pass (`web`, `ios`, `android` or `mac`; in a terminal, leave `--platform` out and it asks), writes `verify.config.ts` and an example script, signs you in through the browser on the first interactive run, and prints the command that runs the example. With no app id, the iOS and Android examples open the built-in Settings app, so they run on a new account before you upload anything. To skip the config, run `npm install @revyl/verify` and save the example above as `verify/check.mts`, then run `node verify/check.mts`. [Getting started](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/getting-started.md) covers sign-in, your own app, and [CI](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/ci.md).
|
|
45
45
|
|
|
46
|
-
For finished projects, see [`examples/`](https://github.com/RevylAI/verify/tree/v0.6.
|
|
46
|
+
For finished projects, see [`examples/`](https://github.com/RevylAI/verify/tree/v0.6.1/examples/): a [web store](https://github.com/RevylAI/verify/tree/v0.6.1/examples/web-store/), [mobile Settings](https://github.com/RevylAI/verify/tree/v0.6.1/examples/mobile-settings/), a [Mac workspace](https://github.com/RevylAI/verify/tree/v0.6.1/examples/mac-workspace/), a small [agent platform](https://github.com/RevylAI/verify/tree/v0.6.1/examples/agent-platform/) that runs web and iOS side by side, and [your own model](https://github.com/RevylAI/verify/tree/v0.6.1/examples/byo-model/) (with [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/examples/byo_model.py) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/examples/byomodel/main.go) versions).
|
|
47
47
|
|
|
48
48
|
## Exact actions
|
|
49
49
|
|
|
@@ -60,7 +60,7 @@ await session.instruction('Accept the terms if they are shown'); // the age
|
|
|
60
60
|
await session.validation('The welcome screen is shown');
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
`doubleTap`, `typeFocused`, `back`, `goHome`, `openUrl`, `launchApp`, `locate` and `screenSize` round them out; [which call works where](#which-call-works-where) shows the platform limits. Early access. Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. On a Mac computer's screen, `tap` (by point or by description), `screenSize`, `typeFocused` and `pressKey` are new in TypeScript 0.6.0, Python 0.4.0 and Go v0.5.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
63
|
+
`doubleTap`, `typeFocused`, `back`, `goHome`, `openUrl`, `launchApp`, `locate` and `screenSize` round them out; [which call works where](#which-call-works-where) shows the platform limits. Early access. Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. On a Mac computer's screen, `tap` (by point or by description), `screenSize`, `typeFocused` and `pressKey` are new in TypeScript 0.6.0, Python 0.4.0 and Go v0.5.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#exact-actions) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#exact-actions) READMEs show them with each language's names. The [web](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/web.md#exact-actions) and [mobile](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/mobile.md#exact-actions) guides have runnable scripts, and [api.md](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/api.md#exact-actions) lists every call.
|
|
64
64
|
|
|
65
65
|
## Your own model
|
|
66
66
|
|
|
@@ -74,7 +74,7 @@ await session.instruction('Open Privacy', { model: 'openai/gpt-5.5' });
|
|
|
74
74
|
await open('ios', { model: { id: 'qwen-3.8-27b', baseURL: 'https://api.cerebras.ai/v1', apiKey: process.env.CEREBRAS_API_KEY } });
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0; the [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
77
|
+
Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0; the [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#your-own-model) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#your-own-model) READMEs show them with each language's names. Built in: `anthropic`, `openai`, `google`, `openrouter`, `groq`, `cerebras`, `xai` and `ollama`; anything OpenAI-compatible works through `baseURL`. Early access; [Use your own model](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/own-model.md) covers the providers, picking a model, what Revyl still sees, limits and troubleshooting.
|
|
78
78
|
|
|
79
79
|
## Packages
|
|
80
80
|
|
|
@@ -82,8 +82,8 @@ Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v
|
|
|
82
82
|
| --- | --- | --- |
|
|
83
83
|
| [`@revyl/verify`](https://www.npmjs.com/package/@revyl/verify) | `npm install @revyl/verify` | TypeScript SDK and the `verify` CLI (`init`, `login`, `logout`, `whoami`). Published on npm, Node.js 22.18 or later. |
|
|
84
84
|
| [`revyl-verify`](https://www.npmjs.com/package/revyl-verify) (npm) | `npm install revyl-verify` | Alias of `@revyl/verify` at the same version. |
|
|
85
|
-
| [Go module](https://github.com/RevylAI/verify/tree/go/v0.5.
|
|
86
|
-
| [`revyl-verify`](https://pypi.org/project/revyl-verify/) (PyPI) | `pip install revyl-verify` or `uv add revyl-verify` | Python SDK, published on PyPI. Python 3.10 or later, sync and asyncio APIs, no CLI; see the [Python guide](https://github.com/RevylAI/verify/blob/v0.6.
|
|
85
|
+
| [Go module](https://github.com/RevylAI/verify/tree/go/v0.5.1/go) | `go get github.com/RevylAI/verify/go@v0.5.1` | Published as the `go/v0.5.1` tag, Go 1.26.9 or later. Calls return errors instead of throwing. |
|
|
86
|
+
| [`revyl-verify`](https://pypi.org/project/revyl-verify/) (PyPI) | `pip install revyl-verify` or `uv add revyl-verify` | Python SDK, published on PyPI. Python 3.10 or later, sync and asyncio APIs, no CLI; see the [Python guide](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md). |
|
|
87
87
|
|
|
88
88
|
## Platforms
|
|
89
89
|
|
|
@@ -116,16 +116,16 @@ Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v
|
|
|
116
116
|
|
|
117
117
|
A call a platform doesn't support throws `NOT_AVAILABLE_ON_PLATFORM`, and its message names the alternative.
|
|
118
118
|
|
|
119
|
-
Web is available to every organization. Mac computers are
|
|
119
|
+
Web is available to every organization. Mac computers are available to organizations on a current paid Revyl plan and have a server-bounded lifetime; see [computers](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/computers.md).
|
|
120
120
|
|
|
121
121
|
## Documentation
|
|
122
122
|
|
|
123
|
-
The [documentation](https://github.com/RevylAI/verify/tree/v0.6.
|
|
123
|
+
The [documentation](https://github.com/RevylAI/verify/tree/v0.6.1/packages/verify/docs/) covers the [API](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/api.md), [configuration](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/configuration.md), [web](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/web.md), [mobile](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/mobile.md), [computers](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/computers.md), [CI](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/ci.md), [your own model](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/own-model.md), [errors and troubleshooting](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/errors.md), [coding agents](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/agents.md), and [live end-to-end results](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/end-to-end.md). The npm package ships these pages in `node_modules/@revyl/verify/docs/`, with an [llms.txt](https://github.com/RevylAI/verify/blob/v0.6.1/packages/verify/docs/llms.txt) index, so a coding agent can read the docs for the version you installed. The Revyl docs site has an overview at [docs.revyl.com/verify](https://docs.revyl.com/verify).
|
|
124
124
|
|
|
125
125
|
## Status
|
|
126
126
|
|
|
127
|
-
Verify is at 0.x, so APIs can still change between minor releases; the [changelog](https://github.com/RevylAI/verify/blob/v0.6.
|
|
127
|
+
Verify is at 0.x, so APIs can still change between minor releases; the [changelog](https://github.com/RevylAI/verify/blob/v0.6.1/CHANGELOG.md) records each release. See [Contributing](https://github.com/RevylAI/verify/blob/v0.6.1/CONTRIBUTING.md) and [Releasing](https://github.com/RevylAI/verify/blob/v0.6.1/RELEASING.md) to work on Verify.
|
|
128
128
|
|
|
129
129
|
## License
|
|
130
130
|
|
|
131
|
-
[Apache 2.0](https://github.com/RevylAI/verify/blob/v0.6.
|
|
131
|
+
[Apache 2.0](https://github.com/RevylAI/verify/blob/v0.6.1/LICENSE).
|
package/dist/api/client.js
CHANGED
|
@@ -46,8 +46,12 @@ export class RevylClient {
|
|
|
46
46
|
throw apiError(method, path, response);
|
|
47
47
|
return parseJson(response, `${method} ${path}`);
|
|
48
48
|
}
|
|
49
|
-
startDevice(request, signal) {
|
|
50
|
-
|
|
49
|
+
async startDevice(request, signal) {
|
|
50
|
+
const path = '/api/v1/execution/start_device';
|
|
51
|
+
const response = await this.send('POST', path, { body: request, retry: false, timeoutMs: 120_000, signal });
|
|
52
|
+
if (response.status < 200 || response.status >= 300)
|
|
53
|
+
throw (request.platform !== 'web' && mobileStartRefusal(response)) || apiError('POST', path, response);
|
|
54
|
+
return parseJson(response, `POST ${path}`);
|
|
51
55
|
}
|
|
52
56
|
getDeviceSession(sessionId, signal) {
|
|
53
57
|
return this.json('GET', `/api/v1/execution/device-sessions/${encodeURIComponent(sessionId)}`, { signal });
|
|
@@ -216,6 +220,21 @@ const START_ERROR_DETAILS = new Set([
|
|
|
216
220
|
export function responseRefusalReason(response) {
|
|
217
221
|
return responseKnownDetail(response, REFUSAL_REASONS);
|
|
218
222
|
}
|
|
223
|
+
function mobileStartRefusal(response) {
|
|
224
|
+
if (response.status !== 400 && response.status !== 422 || edgeBlockedError(response))
|
|
225
|
+
return undefined;
|
|
226
|
+
let detail;
|
|
227
|
+
try {
|
|
228
|
+
detail = JSON.parse(new TextDecoder().decode(response.body))?.detail;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
if (typeof detail !== 'string' || /^[a-z0-9_]*$/.test(detail.trim()))
|
|
234
|
+
return undefined;
|
|
235
|
+
const message = detail.trim().slice(0, 500);
|
|
236
|
+
return new VerifyError('INVALID_ARGUMENT', `Revyl refused to start the session (HTTP ${response.status}): ${/[.!?]$/.test(message) ? message : `${message}.`} Change the target to a value Revyl accepts and run again.`, { httpStatus: response.status });
|
|
237
|
+
}
|
|
219
238
|
function responseKnownDetail(response, codes) {
|
|
220
239
|
try {
|
|
221
240
|
const parsed = JSON.parse(new TextDecoder().decode(response.body));
|
package/dist/cli/init.js
CHANGED
|
@@ -99,9 +99,9 @@ ${target}
|
|
|
99
99
|
});
|
|
100
100
|
`;
|
|
101
101
|
}
|
|
102
|
-
function scriptTemplate({ platform, appId }) {
|
|
102
|
+
function scriptTemplate({ platform, appId, url }) {
|
|
103
103
|
if (platform === 'mac') {
|
|
104
|
-
return `// Mac computers
|
|
104
|
+
return `// Mac computers need a current paid Revyl plan; if yours can't start one, ask support@revyl.ai.
|
|
105
105
|
import assert from 'node:assert/strict';
|
|
106
106
|
import { open } from '@revyl/verify';
|
|
107
107
|
|
|
@@ -117,16 +117,19 @@ try {
|
|
|
117
117
|
}
|
|
118
118
|
`;
|
|
119
119
|
}
|
|
120
|
-
const steps = platform === 'web'
|
|
120
|
+
const steps = platform === 'web' && (url === undefined || /^https:\/\/example\.com\/?$/.test(url))
|
|
121
121
|
? `await session.instruction('Follow the link on the page');
|
|
122
122
|
await session.validation('A page about domains reserved for documentation is shown');`
|
|
123
|
-
:
|
|
124
|
-
?
|
|
123
|
+
: platform === 'web'
|
|
124
|
+
? `// Checks only that ${url} loads. Replace it with steps for your app, such as an instruction followed by a validation.
|
|
125
|
+
await session.validation('The page has finished loading and shows its content, not an error page');`
|
|
126
|
+
: !appId && platform === 'ios'
|
|
127
|
+
? `await session.instruction('Open General, then About');
|
|
125
128
|
await session.validation('The screen shows the operating system version');`
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
: !appId && platform === 'android'
|
|
130
|
+
? `await session.instruction('Open the screen that shows information about this device, such as About or About phone, then scroll or navigate until the operating system version is visible');
|
|
128
131
|
await session.validation('The screen shows the version of the operating system');`
|
|
129
|
-
|
|
132
|
+
: `await session.instruction('Wait for the app to finish opening and show its first screen');
|
|
130
133
|
await session.validation('The app has opened and shows its first screen without an error');`;
|
|
131
134
|
return `import { open } from '${PACKAGE_NAME}';
|
|
132
135
|
|
package/dist/cli/main.js
CHANGED
|
@@ -126,7 +126,7 @@ async function initCommand(args) {
|
|
|
126
126
|
process.stdout.write(`Created ${result.created.join(' and ')}${result.gitignoreUpdated ? ', and added .verify/ to .gitignore' : ''}.\n`);
|
|
127
127
|
await signInAndCheck(interactive);
|
|
128
128
|
const steps = answers.platform === 'mac'
|
|
129
|
-
? [
|
|
129
|
+
? ["Mac computers need a current paid Revyl plan; if yours can't start one, ask support@revyl.ai.", 'Run: node verify/example.mts']
|
|
130
130
|
: answers.appId
|
|
131
131
|
? ['Run: node verify/example.mts']
|
|
132
132
|
: ['Run: node verify/example.mts', 'To test your own app, put its Revyl app id in verify.config.ts in place of the Settings bundle id.'];
|
package/dist/computer-session.js
CHANGED
|
@@ -11,7 +11,7 @@ import { DeviceSession, checkLocation, pngSize } from './session.js';
|
|
|
11
11
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12
12
|
const STATES = new Set(['starting', 'active', 'closing', 'stopped', 'failed', 'owner_lost']);
|
|
13
13
|
const MAX_OUTPUT_BYTES = 1_048_576;
|
|
14
|
-
const COMPUTER_AVAILABILITY = '
|
|
14
|
+
const COMPUTER_AVAILABILITY = 'Mac computers need a current paid Revyl plan, and Linux computers are not generally available. Ask support@revyl.ai about access.';
|
|
15
15
|
const COMPUTER_CAPACITY = 'Computer admission was refused because of queued work (including iOS) or the concurrency limit. Verify will not retry the start.';
|
|
16
16
|
const ERROR_CODES = new Set(['computer_not_enabled', 'run_closed', 'inaccessible', 'invalid_handle', 'operation_not_found', 'owner_unavailable', 'invalid_request', 'unauthenticated', 'forbidden', 'runtime_unavailable', 'start_failed', 'computer_limit', 'request_conflict', 'run_conflict', 'evidence_conflict', 'evidence_unavailable', 'authentication_unavailable', 'operation_limit', 'screen_starting', 'screen_unavailable', 'screen_control_held', 'screen_control_lost', 'screen_input_unavailable', 'screen_input_uncertain', 'screen_key_unsupported', 'screen_text_unsupported', 'screen_target_not_found', 'screen_target_unavailable']);
|
|
17
17
|
const COMPUTER_KEYS = { enter: 'Return', backspace: 'BackSpace', tab: 'Tab', escape: 'Escape', delete: 'Delete', space: 'space', arrowup: 'Up', arrowdown: 'Down', arrowleft: 'Left', arrowright: 'Right', home: 'Home', end: 'End', pageup: 'Page_Up', pagedown: 'Page_Down' };
|
package/docs/agents.md
CHANGED
|
@@ -19,7 +19,7 @@ This page is for AI coding agents (Claude Code, Cursor, Codex, and others) that
|
|
|
19
19
|
await session.close();
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
|
-
4.
|
|
22
|
+
4. Name it `.mts` and run it with `node path/to/script.mts`; Node runs a `.mts` file as an ES module whatever `package.json` says, while a `.ts` file fails to import in a CommonJS project. Share the session link from the first `[verify]` line with the user, so they can watch.
|
|
23
23
|
5. Read the outcome from the exit code and stderr. Each step prints `✓` or `✗` with its text; a failure prints `CODE: message`, ending with the session link. Look at any screenshot you saved before changing the script or the app.
|
|
24
24
|
|
|
25
25
|
## Exact actions and coordinates
|
|
@@ -53,11 +53,11 @@ try {
|
|
|
53
53
|
}
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
The [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
56
|
+
The [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#exact-actions) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#exact-actions) READMEs state the same rule with each language's names. [api.md](api.md#exact-actions) lists every call and its errors.
|
|
57
57
|
|
|
58
58
|
## Rules
|
|
59
59
|
|
|
60
|
-
Mac computers are
|
|
60
|
+
Mac computers are available to organizations on a current paid Revyl plan. Ask before starting a computer, as for a device; do not repeat an uncertain start/stop to probe availability.
|
|
61
61
|
|
|
62
62
|
For computer work, use structured `exec(['program', 'arg'])`, `readFile`, `writeFile`, `stat`, and run-owned handles from `processes()`/`terminate(id)`. Check command output with ordinary assertions and close in `finally`; screenshots are supported, but instruction/validation are not. To use the screen, read a point off `screenshot()` and `tap({ x, y })` it, or describe it with `tap({ target })`, and type with `typeFocused(text, { clear: false })`. A described click takes several seconds, because Revyl takes a screenshot and finds the element first. It can pick a look-alike, and when the target isn't on the screen it can still click something else instead of failing. So check the point it returns or take a screenshot afterwards, and for anything that's hard to undo, read the point off `screenshot()` and use `tap({ x, y })`. After `ACTION_UNCERTAIN`, take a screenshot before you act again. Do not fall back to agent steps on computers or shell/file methods on mobile/web. See [computers.md](computers.md) for limits. Starting a computer is a paid external action and needs the same approval as starting a device.
|
|
63
63
|
|
package/docs/api.md
CHANGED
|
@@ -8,7 +8,7 @@ import { attach, open, defineConfig, VerifyError, isVerifyError } from '@revyl/v
|
|
|
8
8
|
|
|
9
9
|
Starts a Revyl cloud browser, device, or Mac computer. Mobile first-screen readiness is [best-effort](mobile.md#steps), not a foreground/rendered-readiness guarantee. Computer starts retain a 10-minute default timeout; an unclaimed start may fail after 120 seconds with no-host context.
|
|
10
10
|
|
|
11
|
-
Mac computers are
|
|
11
|
+
Mac computers are available to organizations on a current paid Revyl plan.
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
const web = await open('web'); // a target named in verify.config.ts
|
|
@@ -63,20 +63,20 @@ Starts a child app session inside this computer, returning the normal session AP
|
|
|
63
63
|
Mac supports Web and iOS children. The server remains authoritative for access, capability and capacity. Children require and share the parent's known deadline. Closing a child leaves the parent running; closing the parent cancels pending starts and gives child cleanup at most five seconds total before requesting confirmed computer release. The parent stop also stops any remaining children, so a slow child cannot prevent that request. A failed child start never closes the parent.
|
|
64
64
|
|
|
65
65
|
```ts
|
|
66
|
-
const computer = await attach(existingComputerId, { log: false });
|
|
66
|
+
const computer = await attach(existingComputerId, { stopOnClose: false, log: false }); // not yours, so close() leaves it running
|
|
67
67
|
try {
|
|
68
68
|
const web = await computer.open({
|
|
69
69
|
platform: 'web',
|
|
70
70
|
app: { appId: webAppId, buildId: externalBuildId },
|
|
71
71
|
});
|
|
72
|
-
await web.navigate('
|
|
73
|
-
await web.validation('The
|
|
72
|
+
await web.navigate('https://www.saucedemo.com');
|
|
73
|
+
await web.validation('The Swag Labs login form is shown');
|
|
74
74
|
} finally {
|
|
75
75
|
await computer.close();
|
|
76
76
|
}
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
The initial Web build uses HTTPS. After start, `navigate()` can also reach `http://localhost:<port>` on the computer, but only when a service is already listening there, such as one an earlier step of a `revyl-macos` job started. Verify has no call that starts one, and a process started through `exec()` ends when the command returns. Leave out `stopOnClose: false` only for a computer your script owns: then `close()` stops it.
|
|
80
80
|
|
|
81
81
|
## session.navigate(url)
|
|
82
82
|
|
|
@@ -84,7 +84,7 @@ Web only, hosted or normal. Sends one deterministic `open_url` action and checks
|
|
|
84
84
|
|
|
85
85
|
## Exact actions
|
|
86
86
|
|
|
87
|
-
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. On a Mac computer's screen, `tap` (by point or by description), `screenSize`, `typeFocused` and `pressKey` are new in TypeScript 0.6.0, Python 0.4.0 and Go v0.5.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
87
|
+
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. On a Mac computer's screen, `tap` (by point or by description), `screenSize`, `typeFocused` and `pressKey` are new in TypeScript 0.6.0, Python 0.4.0 and Go v0.5.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#exact-actions) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#exact-actions) READMEs show them with each language's names. Web, iOS and Android sessions, and a Mac computer's screen, take device actions that need no agent.
|
|
88
88
|
|
|
89
89
|
| Call | Web | iOS | Android | Mac computer |
|
|
90
90
|
| --- | --- | --- | --- | --- |
|
|
@@ -182,7 +182,7 @@ When inspecting `revyl device report --session-id <id>`, read validation verdict
|
|
|
182
182
|
|
|
183
183
|
## Your own model
|
|
184
184
|
|
|
185
|
-
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0; the [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
185
|
+
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0; the [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#your-own-model) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#your-own-model) READMEs show them with each language's names. Runs instructions and validations on a model you choose, in your process, instead of Revyl's agent. Revyl still provides the browser or device. Leave `model` out and Revyl's agent runs the step, as before.
|
|
186
186
|
|
|
187
187
|
```ts
|
|
188
188
|
const session = await open('ios', { model: 'anthropic/claude-sonnet-5-5' }); // every step on your model
|
package/docs/ci.md
CHANGED
|
@@ -4,7 +4,7 @@ Verify is a library, so it runs wherever your code runs. Browsers, devices, and
|
|
|
4
4
|
|
|
5
5
|
## A script in GitHub Actions
|
|
6
6
|
|
|
7
|
-
Add `REVYL_API_KEY` as a repository secret, then run your script with `node`. A failed instruction or validation makes the script exit non-zero, which fails the job.
|
|
7
|
+
Add `REVYL_API_KEY` as a repository secret, then run your script with `node`. Name it `.mts`, as `init` does, so Node runs it as an ES module whatever your `package.json` says. A failed instruction or validation makes the script exit non-zero, which fails the job.
|
|
8
8
|
|
|
9
9
|
```yaml
|
|
10
10
|
name: Verify
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
node-version: 24
|
|
23
23
|
cache: npm
|
|
24
24
|
- run: npm ci
|
|
25
|
-
- run: node verify/checkout.
|
|
25
|
+
- run: node verify/checkout.mts
|
|
26
26
|
env:
|
|
27
27
|
REVYL_API_KEY: ${{ secrets.REVYL_API_KEY }}
|
|
28
28
|
- if: ${{ !cancelled() }}
|
package/docs/computers.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Mac computers
|
|
1
|
+
# Mac computers
|
|
2
2
|
|
|
3
|
-
Verify opens a Revyl cloud macOS computer for commands, files, processes, screenshots, and clicks and keys on its screen. It does not open an assigned physical computer. Mac computers are
|
|
3
|
+
Verify opens a Revyl cloud macOS computer for commands, files, processes, screenshots, and clicks and keys on its screen. It does not open an assigned physical computer. Mac computers are available to organizations on a current paid Revyl plan. If yours can't start one, ask [support@revyl.ai](mailto:support@revyl.ai).
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
export REVYL_API_KEY=...
|
|
@@ -124,7 +124,7 @@ The HTTPS URL is signed and short-lived. Keep it private, including its query st
|
|
|
124
124
|
|
|
125
125
|
## Availability and errors
|
|
126
126
|
|
|
127
|
-
Mac computers are
|
|
127
|
+
Mac computers are available to organizations on a current paid Revyl plan. A `503 runtime_unavailable` or typed `computer_not_enabled` becomes `NOT_AVAILABLE_ON_PLATFORM` with this availability guidance. A `429 computer_limit` becomes `COMPUTER_LIMIT`: queued work (including iOS) or the concurrency limit can cause it, and the response does not identify which. Verify does not retry the create or send a stop after these definite admission refusals. `operation_limit` remains `SESSION_BUSY`. Availability is determined by the server.
|
|
128
128
|
|
|
129
129
|
The default `startTimeout` remains 600000 ms; override it explicitly if needed. An unclaimed start can transition to `failed` with `failure_reason: 'no_host'` after 120 seconds from create. Verify stops readiness polling and throws `SESSION_START_FAILED` with that context, then attempts bounded cleanup. This is not a 120-second timeout for every start: claimed guests may take longer. `device_limit` also yields `SESSION_START_FAILED`, with queued-work/concurrency context. A start timeout or unconfirmed close does not prove resources were released. Inspect the session and contact support rather than blindly repeating a start or stop.
|
|
130
130
|
|
package/docs/configuration.md
CHANGED
|
@@ -8,8 +8,8 @@ import { defineConfig } from '@revyl/verify';
|
|
|
8
8
|
export default defineConfig({
|
|
9
9
|
targets: {
|
|
10
10
|
web: { platform: 'web', app: { appId: '…', url: 'https://example.com' }, viewport: { width: 1280, height: 800 } },
|
|
11
|
-
ios: { platform: 'ios', app: { appId: '…' }, device: { model: 'iPhone 16', osVersion: '18.5' } },
|
|
12
|
-
pixel: { platform: 'android', app: { buildId: '…' }, device: { model: 'Pixel
|
|
11
|
+
ios: { platform: 'ios', app: { appId: '…' }, device: { model: 'iPhone 16', osVersion: 'iOS 18.5' } },
|
|
12
|
+
pixel: { platform: 'android', app: { buildId: '…' }, device: { model: 'Pixel 7', osVersion: 'Android 14' } },
|
|
13
13
|
mac: { platform: 'mac' },
|
|
14
14
|
},
|
|
15
15
|
stepTimeout: 240_000,
|
|
@@ -20,7 +20,7 @@ Unknown keys are rejected, so a typo fails loudly instead of being ignored.
|
|
|
20
20
|
|
|
21
21
|
## Top-level options
|
|
22
22
|
|
|
23
|
-
Mac
|
|
23
|
+
Mac computers are available to organizations on a current paid Revyl plan. See [computer availability](computers.md#availability-and-errors).
|
|
24
24
|
|
|
25
25
|
| Option | Default | Meaning |
|
|
26
26
|
| --- | --- | --- |
|
|
@@ -50,7 +50,7 @@ Mac targets are early access. Ask support@revyl.ai about access. See [computer a
|
|
|
50
50
|
| `app.buildId` | An exact Revyl build to install. |
|
|
51
51
|
| `app.artifactUrl` | An HTTPS URL of an `.apk`, `.app.zip`, or `.ipa` to install. |
|
|
52
52
|
| `app.bundleId` | An app already on the device to launch instead, such as a system app. |
|
|
53
|
-
| `device` | `{ model?, osVersion? }`, for example `{ model: 'Pixel
|
|
53
|
+
| `device` | `{ model?, osVersion? }`, written as Revyl names them, for example `{ model: 'iPhone 16', osVersion: 'iOS 18.5' }` or `{ model: 'Pixel 7', osVersion: 'Android 14' }`. Revyl picks its default for a value you leave out. A model or OS version Revyl doesn't offer, or a pair that doesn't go together, throws `INVALID_ARGUMENT` listing the values it accepts, and no session starts |
|
|
54
54
|
| `startTimeout` | Milliseconds to wait for the device. Default 600000. |
|
|
55
55
|
| `idleTimeoutSeconds` | Default 600. |
|
|
56
56
|
|
package/docs/end-to-end.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Verify working end to end
|
|
2
2
|
|
|
3
|
+
**Historical record.** This page documents the 0.1.0 and 0.2.0 runs of October 2026 and is kept for its method. It does not describe the current release: the [changelog](https://github.com/RevylAI/verify/blob/main/CHANGELOG.md) and the guides do.
|
|
4
|
+
|
|
3
5
|
These live runs were made on **2026-10-27**. The baseline uses source commit [`6029513369f13e73914b550d0cd26ece615b4e13`](https://github.com/RevylAI/verify/tree/6029513369f13e73914b550d0cd26ece615b4e13); the separate published-package check used `@revyl/verify@0.1.0`. The [re-verification below](#re-verification-at-061e5cfa) uses `061e5cfa31c5489aa304c2b640bbaf40e3d88561`, including an unpublished packed 0.2.0 tarball. Neither is a publication announcement.
|
|
4
6
|
|
|
5
7
|
Only reviewed public scripts, sanitized transcripts, result projections, and two reviewed screenshots were used here. No private reports, device identifiers, session links, signed recording URLs, or recordings are published.
|
package/docs/errors.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
`web_runtime_unavailable` does not distinguish full capacity from an unavailable runtime. `computer_limit` does not distinguish queued work from concurrency exhaustion. Inspect these fields to classify refusal without parsing prose; do not infer a specific cause or automatically start a replacement session.
|
|
20
20
|
|
|
21
|
-
Ordinary start errors retain recognized safe server diagnostic codes such as `web_app_required` in the message even when they are not typed refusal reasons.
|
|
21
|
+
Ordinary start errors retain recognized safe server diagnostic codes such as `web_app_required` in the message even when they are not typed refusal reasons. An iOS or Android start that Revyl refuses as invalid (HTTP 400 or 422), such as a device model or OS version it doesn't offer, throws `INVALID_ARGUMENT` with Revyl's explanation, which lists the values it accepts; nothing was started. Other server messages and payloads, including every Web and hosted start's, are not copied into startup diagnostics.
|
|
22
22
|
|
|
23
23
|
Web navigation timeouts expose `reason: 'request_timeout'` with HTTP 504 and `code: 'ACTION_UNCERTAIN'`: the action budget expired before navigation was confirmed, but the request may still commit and the session remains open. A normalized `protocol_error` also preserves uncertainty and its HTTP status. Neither error causes Verify to replay navigation or close the session. Inspect the live page before deciding whether to navigate again.
|
|
24
24
|
|
|
@@ -37,7 +37,7 @@ try {
|
|
|
37
37
|
|
|
38
38
|
| Code | What happened | What to do |
|
|
39
39
|
| --- | --- | --- |
|
|
40
|
-
| `INVALID_ARGUMENT` | A call got a bad value: an unknown target name, an empty step, two steps at once on one session, a point outside the screenshot, `typeFocused` on a computer without `{ clear: false }
|
|
40
|
+
| `INVALID_ARGUMENT` | A call got a bad value: an unknown target name, an empty step, two steps at once on one session, a point outside the screenshot, `typeFocused` on a computer without `{ clear: false }`, or a device model or OS version Revyl doesn't offer | The message names the argument, and for a device, the values Revyl accepts |
|
|
41
41
|
| `CONFIG_NOT_FOUND` | `open('name')` found no `verify.config.ts` at or above the current folder | Run `npx @revyl/verify init`, pass `options.config`, or pass a target object |
|
|
42
42
|
| `CONFIG_INVALID` | The config failed validation or did not load | The message names the exact option and the rule |
|
|
43
43
|
| `AUTH_MISSING` | No `REVYL_API_KEY` and no saved login | Run `npx @revyl/verify login` in a terminal, or set `REVYL_API_KEY` |
|
package/docs/getting-started.md
CHANGED
|
@@ -86,7 +86,7 @@ The generated iOS and Android targets open Settings. To test your own app, repla
|
|
|
86
86
|
|
|
87
87
|
- **Web:** create a Web app in Revyl (see [web.md](web.md#create-the-web-app)) and set `app.url` to a public HTTPS URL. Revyl's cloud browser cannot reach `localhost`.
|
|
88
88
|
- **iOS and Android:** upload a build to the app in Revyl, for example with `revyl build upload`; each session installs the newest one. See [mobile.md](mobile.md).
|
|
89
|
-
- **Mac:** computers are
|
|
89
|
+
- **Mac:** computers are available to organizations on a current paid Revyl plan. Agent instruction/validation are unavailable. See [computers.md](computers.md#availability-and-errors).
|
|
90
90
|
|
|
91
91
|
## Run the script
|
|
92
92
|
|
package/docs/llms.txt
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Docs
|
|
6
6
|
|
|
7
|
-
Mac computers are
|
|
7
|
+
Mac computers are available to organizations on a current paid Revyl plan. See computers.md#availability-and-errors.
|
|
8
8
|
|
|
9
9
|
- [Getting started](getting-started.md): install, authenticate, init, run a script
|
|
10
10
|
- [API](api.md): open(), attach(), hosted children, navigate(), report(), agent steps, screenshot(), exec(), file/process methods, close()
|
|
11
11
|
- [Configuration](configuration.md): verify.config.ts targets, environment variables, the init and whoami commands
|
|
12
12
|
- [Web](web.md): Revyl web sessions, URLs and builds, sign-in, steps, and exact actions
|
|
13
13
|
- [Mobile](mobile.md): iOS and Android devices, installing apps, and exact actions
|
|
14
|
-
- [Computers](computers.md#availability-and-errors): Mac
|
|
14
|
+
- [Computers](computers.md#availability-and-errors): Mac availability, commands and files, the screen (clicks, typing and keys), expiry, capacity errors, recording metadata, and confirmed release
|
|
15
15
|
- [Verify working end to end](end-to-end.md): live verification scope, observed outcomes, and limits of the evidence
|
|
16
16
|
- [CI and test runners](ci.md): GitHub Actions, node:test, Vitest, Jest, Playwright Test
|
|
17
17
|
- [Use your own model](own-model.md): run instructions and validations on Claude, GPT, Gemini, a local model or any OpenAI-compatible endpoint; providers, limits, privacy and troubleshooting
|
package/docs/mobile.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
An `ios` or `android` target opens your app on a Revyl cloud simulator or emulator.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
{ platform: 'ios', app: { appId: '…' }, device: { model: 'iPhone 16', osVersion: '18.5' } }
|
|
7
|
-
{ platform: 'android', app: { buildId: '…' }, device: { model: 'Pixel
|
|
6
|
+
{ platform: 'ios', app: { appId: '…' }, device: { model: 'iPhone 16', osVersion: 'iOS 18.5' } }
|
|
7
|
+
{ platform: 'android', app: { buildId: '…' }, device: { model: 'Pixel 7', osVersion: 'Android 14' } }
|
|
8
8
|
{ platform: 'android', app: { artifactUrl: 'https://ci.example.com/app-release.apk' } }
|
|
9
9
|
{ platform: 'ios', app: { bundleId: 'com.apple.Preferences' } } // an app already on the device
|
|
10
10
|
```
|
|
@@ -18,17 +18,17 @@ An `ios` or `android` target opens your app on a Revyl cloud simulator or emulat
|
|
|
18
18
|
|
|
19
19
|
## Devices
|
|
20
20
|
|
|
21
|
-
`device.model` and `device.osVersion` pick the simulator or emulator. Without them, Revyl picks its default for the platform. To run the same script on several devices, give each its own target and open them one after another or in parallel:
|
|
21
|
+
`device.model` and `device.osVersion` pick the simulator or emulator. Write them as Revyl names them: `'iOS 18.5'` and `'Android 14'`, not `'18.5'` or `'14'`. Without them, Revyl picks its default for the platform, and with only a model, its default OS version, which that model must support. A value Revyl doesn't offer throws `INVALID_ARGUMENT` before any session starts, and the message lists the models or versions it accepts. To run the same script on several devices, give each its own target and open them one after another or in parallel:
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
24
|
targets: {
|
|
25
|
-
'iphone-
|
|
26
|
-
'iphone-16': { platform: 'ios', app: { appId }, device: { model: 'iPhone 16' } },
|
|
25
|
+
'iphone-air': { platform: 'ios', app: { appId }, device: { model: 'iPhone Air' } },
|
|
26
|
+
'iphone-16': { platform: 'ios', app: { appId }, device: { model: 'iPhone 16', osVersion: 'iOS 18.5' } },
|
|
27
27
|
},
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
```ts
|
|
31
|
-
for (const name of ['iphone-
|
|
31
|
+
for (const name of ['iphone-air', 'iphone-16']) {
|
|
32
32
|
const session = await open(name);
|
|
33
33
|
try {
|
|
34
34
|
await session.validation('The onboarding screen fits without overlapping text');
|
|
@@ -46,11 +46,11 @@ After connection and any explicit bundle launch, `open()` makes a best-effort fi
|
|
|
46
46
|
|
|
47
47
|
The generated mobile example starts with an instruction to wait for the first screen before validating it. For your own scripts, make the first instruction describe the screen or action you actually need; a screenshot with content can still show a loading screen or another app.
|
|
48
48
|
|
|
49
|
-
For Android Settings, instruct the agent to scroll or navigate until the OS version is visible before validating it
|
|
49
|
+
For Android Settings (`bundleId: 'com.android.settings'`), instruct the agent to scroll or navigate until the OS version is visible before validating it, as in `instruction('Open About phone, then scroll or navigate until the Android version is visible')`. Opening About alone can leave the version offscreen.
|
|
50
50
|
|
|
51
51
|
## Exact actions
|
|
52
52
|
|
|
53
|
-
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
53
|
+
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#exact-actions) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#exact-actions) READMEs show them with each language's names. When you know exactly what to press, skip the agent. Exact actions run on the device as given, with no model, and mix freely with `instruction()` and `validation()` in one script:
|
|
54
54
|
|
|
55
55
|
```ts
|
|
56
56
|
import { open } from '@revyl/verify';
|
|
@@ -66,10 +66,10 @@ try {
|
|
|
66
66
|
await session.swipe('down'); // the finger moves down, so the list scrolls to the top
|
|
67
67
|
const search = await session.locate('Search field'); // a point in screenshot pixels
|
|
68
68
|
await session.tap(search); // a tap by coordinates
|
|
69
|
-
await session.type(search, '
|
|
69
|
+
await session.type(search, 'Accessibility');
|
|
70
70
|
await session.pressKey('enter');
|
|
71
|
-
await session.instruction('Open the
|
|
72
|
-
await session.validation('The
|
|
71
|
+
await session.instruction('Open the Accessibility result'); // hand the fuzzy part to the agent
|
|
72
|
+
await session.validation('The Accessibility settings are shown');
|
|
73
73
|
} finally {
|
|
74
74
|
await session.close();
|
|
75
75
|
}
|
package/docs/own-model.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Use your own model
|
|
2
2
|
|
|
3
|
-
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0; the [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
3
|
+
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0; the [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#your-own-model) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#your-own-model) READMEs show them with each language's names. Verify normally runs `instruction()` and `validation()` on Revyl's agent. Pass a `model` and the agent loop runs in your process instead, on a model you choose, with your own key. Revyl still provides the cloud browser or device and, by default, finds the elements your model names on screen.
|
|
4
4
|
|
|
5
5
|
Use it when you want a specific model, your own prompts and key, or faster steps on a cheap model. Leave `model` out and nothing changes.
|
|
6
6
|
|
|
@@ -52,7 +52,7 @@ log.Println(step.Model.ID, len(step.Model.Turns), step.Model.InputTokens, step.M
|
|
|
52
52
|
_, err = s.Validation(ctx, "The screen shows the iOS version")
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
The [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
55
|
+
The [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#your-own-model) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#your-own-model) READMEs have the full reference for each.
|
|
56
56
|
|
|
57
57
|
Set `model` on `open()` to run every step on it, or on one step to override it:
|
|
58
58
|
|
|
@@ -67,7 +67,7 @@ The string is `'provider/model'`. Everything after the first slash is the provid
|
|
|
67
67
|
|
|
68
68
|
| Prefix | Key variable | Endpoint | Status |
|
|
69
69
|
| --- | --- | --- | --- |
|
|
70
|
-
| `anthropic/` | `ANTHROPIC_API_KEY` | Anthropic Messages API |
|
|
70
|
+
| `anthropic/` | `ANTHROPIC_API_KEY` | Anthropic Messages API | Run live with Claude Sonnet 5.5 on Revyl iOS, Android and Web sessions in TypeScript, Python and Go, including `grounding: 'model'` on iOS |
|
|
71
71
|
| `openai/` | `OPENAI_API_KEY` | `https://api.openai.com/v1` | Request shape checked; not yet run live |
|
|
72
72
|
| `google/` | `GOOGLE_API_KEY`, or `GEMINI_API_KEY` when it is unset | `https://generativelanguage.googleapis.com/v1beta/openai/` | Request shape checked; not yet run live |
|
|
73
73
|
| `openrouter/` | `OPENROUTER_API_KEY` | `https://openrouter.ai/api/v1` | Request shape checked; not yet run live |
|
|
@@ -97,7 +97,7 @@ Measured in production on Cerebras `qwen-3.8-27b`, a fast vision model (about 0.
|
|
|
97
97
|
| | your model, `grounding: 'revyl'` | pass, 21.2 s | pass, 1.3 s | 4 + 1 | 7,854/355 + 1,380/136 |
|
|
98
98
|
| | your model, `grounding: 'model'` | fail after 20 turns, 64.4 s | | 20 | 52,726 total |
|
|
99
99
|
|
|
100
|
-
Each local turn costs one model call plus one device action: about 3.7 s per turn on iOS and 5.3 s on Web here, most of it the device action and the screen settling. These are two short flows on one model, so treat them as a direction, not a benchmark.
|
|
100
|
+
Each local turn costs one model call plus one device action: about 3.7 s per turn on iOS and 5.3 s on Web here, most of it the device action and the screen settling. These are two short flows on one model, so treat them as a direction, not a benchmark. GPT and Gemini have not been measured yet. Claude Sonnet 5.5 passed with `grounding: 'model'` on iOS Settings in 3 turns; that is one run, so treat `grounding: 'model'` as dependent on the model.
|
|
101
101
|
|
|
102
102
|
Start with the default grounding and the cheapest vision model your provider has. Move to a stronger model if steps run out of turns or pick the wrong elements.
|
|
103
103
|
|
package/docs/web.md
CHANGED
|
@@ -53,7 +53,7 @@ Revyl runs one step at a time on a session. A step sent while another is still r
|
|
|
53
53
|
|
|
54
54
|
## Exact actions
|
|
55
55
|
|
|
56
|
-
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.
|
|
56
|
+
**Early access.** Since TypeScript (`@revyl/verify`) 0.4.0, Python (`revyl-verify`) 0.2.0 and Go v0.3.0. `doubleTap`, `longPress`, `drag`, `typeFocused`, `goHome`, and Web keys and modifiers in `pressKey`, are new in TypeScript 0.5.0, Python 0.3.0 and Go v0.4.0. The [Python](https://github.com/RevylAI/verify/blob/v0.6.1/python/README.md#exact-actions) and [Go](https://github.com/RevylAI/verify/blob/v0.6.1/go/README.md#exact-actions) READMEs show them with each language's names. When you know exactly what to click, skip the agent. Exact actions run in the browser as given, with no model, and mix freely with `instruction()` and `validation()`:
|
|
57
57
|
|
|
58
58
|
```ts
|
|
59
59
|
import { open } from '@revyl/verify';
|
|
@@ -66,6 +66,7 @@ try {
|
|
|
66
66
|
await session.validation('A list of products is shown');
|
|
67
67
|
await session.swipe('up'); // the finger moves up, so the page scrolls down
|
|
68
68
|
await session.instruction('Add the Sauce Labs Onesie to the cart'); // hand the fuzzy part to the agent
|
|
69
|
+
await session.swipe('down'); // back to the top, so the cart icon is on screen
|
|
69
70
|
const cart = await session.locate('Shopping cart icon'); // a point in screenshot pixels
|
|
70
71
|
await session.tap(cart); // a tap by coordinates
|
|
71
72
|
await session.validation('The cart lists the Sauce Labs Onesie');
|