@revyl/verify 0.3.2 → 0.4.0
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 +50 -0
- package/README.md +59 -24
- package/dist/agent/image.d.ts +7 -0
- package/dist/agent/image.js +29 -0
- package/dist/agent/loop.d.ts +97 -0
- package/dist/agent/loop.js +215 -0
- package/dist/agent/model.d.ts +91 -0
- package/dist/agent/model.js +255 -0
- package/dist/agent/providers.d.ts +23 -0
- package/dist/agent/providers.js +58 -0
- package/dist/api/client.d.ts +1 -0
- package/dist/api/client.js +2 -2
- package/dist/auth.js +2 -2
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.js +34 -9
- package/dist/cli/login.js +7 -7
- package/dist/cli/main.js +84 -29
- package/dist/computer-session.d.ts +9 -0
- package/dist/computer-session.js +27 -0
- package/dist/errors.d.ts +2 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -0
- package/dist/open.d.ts +6 -0
- package/dist/open.js +6 -1
- package/dist/session.d.ts +71 -2
- package/dist/session.js +230 -12
- package/docs/README.md +4 -3
- package/docs/agents.md +5 -5
- package/docs/api.md +89 -13
- package/docs/computers.md +9 -11
- package/docs/configuration.md +11 -7
- package/docs/errors.md +7 -5
- package/docs/getting-started.md +22 -17
- package/docs/llms.txt +6 -5
- package/docs/mobile.md +46 -0
- package/docs/own-model.md +216 -0
- package/docs/web.md +56 -1
- package/package.json +2 -3
package/dist/cli/main.js
CHANGED
|
@@ -1,25 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { rm } from 'node:fs/promises';
|
|
2
3
|
import { createInterface } from 'node:readline/promises';
|
|
3
4
|
import { parseArgs } from 'node:util';
|
|
4
5
|
import { RevylClient } from '../api/client.js';
|
|
5
|
-
import { missingCredentialsMessage, resolveCredentials } from '../auth.js';
|
|
6
|
+
import { missingCredentialsMessage, resolveCredentials, revylCredentialsPath } from '../auth.js';
|
|
6
7
|
import { VerifyError, errorMessage, isVerifyError } from '../errors.js';
|
|
7
8
|
import { PACKAGE_NAME, VERSION } from '../version.js';
|
|
8
|
-
import { initProject, validateInitAnswers } from './init.js';
|
|
9
|
+
import { initProject, validateInitAnswers, webAppIdMissingMessage } from './init.js';
|
|
9
10
|
import { installVerify, packageHasVerify } from './install.js';
|
|
10
11
|
import { signIn } from './login.js';
|
|
12
|
+
const INIT_USAGE = `npx ${PACKAGE_NAME} init [--platform ios|android|web|mac] [--app-id <id>] [--url <https-url>] [--force] [--yes] [--no-install]`;
|
|
13
|
+
const DOCS = `https://github.com/RevylAI/verify/tree/v${VERSION}/packages/verify/docs`;
|
|
11
14
|
const HELP = `verify ${VERSION}: open Revyl cloud browsers, devices, and computers from your code
|
|
12
15
|
|
|
13
16
|
Usage
|
|
14
|
-
|
|
15
|
-
Install Verify, write verify.config.ts and an example script,
|
|
17
|
+
${INIT_USAGE}
|
|
18
|
+
Install Verify, write verify.config.ts and an example script, and sign in
|
|
19
|
+
npx ${PACKAGE_NAME} login
|
|
20
|
+
Sign in to Revyl through your browser
|
|
21
|
+
npx ${PACKAGE_NAME} logout
|
|
22
|
+
Remove the saved Revyl login from this computer
|
|
16
23
|
npx ${PACKAGE_NAME} whoami
|
|
17
24
|
Check which Revyl account your credentials belong to
|
|
18
25
|
|
|
19
26
|
Authentication
|
|
20
|
-
|
|
27
|
+
In a terminal, init, login, and your first open() sign you in through your browser and save the
|
|
28
|
+
login to ~/.revyl/credentials.json, which the Revyl CLI shares. In CI, set REVYL_API_KEY instead.
|
|
21
29
|
|
|
22
|
-
Docs:
|
|
30
|
+
Docs: ${DOCS}
|
|
31
|
+
`;
|
|
32
|
+
const INIT_HELP = `Usage: ${INIT_USAGE}
|
|
33
|
+
|
|
34
|
+
Writes verify.config.ts and verify/example.mts, installs Verify when the project lacks it, and signs
|
|
35
|
+
you in through your browser when no credentials are saved.
|
|
36
|
+
|
|
37
|
+
--platform ios, android, web, or mac. Without it, init asks. iOS and Android without --app-id
|
|
38
|
+
open the device's built-in Settings app, so the example runs before you upload anything.
|
|
39
|
+
--app-id The Revyl app to open. Required for web; create a Web app at https://app.revyl.ai first.
|
|
40
|
+
--url The public HTTPS URL a web target opens (default https://example.com).
|
|
41
|
+
--force Overwrite existing files.
|
|
42
|
+
--yes Install Verify without asking.
|
|
43
|
+
--no-install Skip installing Verify.
|
|
44
|
+
|
|
45
|
+
Docs: ${DOCS}/getting-started.md
|
|
23
46
|
`;
|
|
24
47
|
const USAGE_CODES = new Set(['INVALID_ARGUMENT', 'AUTH_MISSING', 'AUTH_REJECTED']);
|
|
25
48
|
export async function main(argv) {
|
|
@@ -37,8 +60,18 @@ export async function main(argv) {
|
|
|
37
60
|
return 0;
|
|
38
61
|
case 'init':
|
|
39
62
|
return initCommand(rest);
|
|
40
|
-
case '
|
|
41
|
-
|
|
63
|
+
case 'login':
|
|
64
|
+
case 'logout':
|
|
65
|
+
case 'whoami': {
|
|
66
|
+
const { values } = parseArgs({ args: rest, options: { help: { type: 'boolean', short: 'h' } } });
|
|
67
|
+
if (values.help) {
|
|
68
|
+
process.stdout.write(HELP);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
if (command === 'login')
|
|
72
|
+
return signInAndCheck(Boolean(process.stdin.isTTY) && !process.env.CI);
|
|
73
|
+
return command === 'logout' ? logoutCommand() : whoamiCommand();
|
|
74
|
+
}
|
|
42
75
|
default:
|
|
43
76
|
process.stderr.write(`Unknown command: ${command}\n\n${HELP}`);
|
|
44
77
|
return 2;
|
|
@@ -54,8 +87,13 @@ async function initCommand(args) {
|
|
|
54
87
|
force: { type: 'boolean' },
|
|
55
88
|
yes: { type: 'boolean' },
|
|
56
89
|
'no-install': { type: 'boolean' },
|
|
90
|
+
help: { type: 'boolean', short: 'h' },
|
|
57
91
|
},
|
|
58
92
|
});
|
|
93
|
+
if (values.help) {
|
|
94
|
+
process.stdout.write(INIT_HELP);
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
59
97
|
const interactive = Boolean(process.stdin.isTTY) && !process.env.CI;
|
|
60
98
|
let answers;
|
|
61
99
|
if (values.platform) {
|
|
@@ -86,44 +124,46 @@ async function initCommand(args) {
|
|
|
86
124
|
answers ??= await askInitQuestions(values['app-id'], values.url);
|
|
87
125
|
const result = await initProject(process.cwd(), answers, { force: values.force ?? false });
|
|
88
126
|
process.stdout.write(`Created ${result.created.join(' and ')}${result.gitignoreUpdated ? ', and added .verify/ to .gitignore' : ''}.\n`);
|
|
127
|
+
await signInAndCheck(interactive);
|
|
128
|
+
const steps = answers.platform === 'mac'
|
|
129
|
+
? ['Mac computers are early access. Ask support@revyl.ai about access.', 'Once your organization has Mac access, run: node verify/example.mts']
|
|
130
|
+
: answers.appId
|
|
131
|
+
? ['Run: node verify/example.mts']
|
|
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.'];
|
|
133
|
+
process.stdout.write([
|
|
134
|
+
'Next:',
|
|
135
|
+
...steps.map((step, index) => ` ${index + 1}. ${step}`),
|
|
136
|
+
'',
|
|
137
|
+
].join('\n'));
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
async function signInAndCheck(interactive) {
|
|
89
141
|
const credentials = await resolveCredentials();
|
|
90
142
|
if (!credentials) {
|
|
91
|
-
if (interactive)
|
|
92
|
-
await signIn();
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
143
|
+
if (!interactive)
|
|
95
144
|
throw new VerifyError('AUTH_MISSING', `${missingCredentialsMessage()} In non-interactive environments, set the REVYL_API_KEY secret.`);
|
|
96
|
-
|
|
145
|
+
await signIn();
|
|
97
146
|
}
|
|
98
147
|
try {
|
|
99
|
-
await whoamiCommand();
|
|
148
|
+
return await whoamiCommand();
|
|
100
149
|
}
|
|
101
150
|
catch (error) {
|
|
102
151
|
if (!interactive || !isVerifyError(error) || error.code !== 'AUTH_REJECTED')
|
|
103
152
|
throw error;
|
|
104
153
|
await signIn({ force: true });
|
|
105
|
-
|
|
154
|
+
return whoamiCommand();
|
|
106
155
|
}
|
|
107
|
-
const steps = [
|
|
108
|
-
'Configure the generated verify.config.ts if needed',
|
|
109
|
-
...(answers.platform === 'mac' ? ['Mac computers are early access. Ask support@revyl.ai about access.'] : []),
|
|
110
|
-
...(answers.platform === 'mac' || answers.appId ? [] : ['Put your Revyl app id in verify.config.ts (or set REVYL_APP_ID)']),
|
|
111
|
-
'node verify/example.ts',
|
|
112
|
-
];
|
|
113
|
-
process.stdout.write([
|
|
114
|
-
'Next:',
|
|
115
|
-
...steps.map((step, index) => ` ${index + 1}. ${step}`),
|
|
116
|
-
'',
|
|
117
|
-
].join('\n'));
|
|
118
|
-
return 0;
|
|
119
156
|
}
|
|
120
157
|
async function askInitQuestions(appId, url) {
|
|
121
158
|
const readline = createInterface({ input: process.stdin, output: process.stdout });
|
|
122
159
|
try {
|
|
123
|
-
const platform = ((await readline.question('What do you want to open? [
|
|
160
|
+
const platform = ((await readline.question('What do you want to open? [ios/android/web/mac] (ios): ')).trim().toLowerCase() || 'ios');
|
|
124
161
|
if (platform === 'mac')
|
|
125
162
|
return validateInitAnswers({ platform, ...(appId ? { appId } : {}), ...(url ? { url } : {}) });
|
|
126
|
-
const
|
|
163
|
+
const question = platform === 'web' ? 'Revyl Web app id (Enter if you have none yet): ' : 'Revyl app id (Enter to use the built-in Settings app): ';
|
|
164
|
+
const id = appId ?? ((await readline.question(question)).trim() || undefined);
|
|
165
|
+
if (platform === 'web' && !id)
|
|
166
|
+
throw new VerifyError('INVALID_ARGUMENT', webAppIdMissingMessage(url));
|
|
127
167
|
const webUrl = platform === 'web' ? (url ?? ((await readline.question('HTTPS URL to open (Enter for https://example.com): ')).trim() || undefined)) : undefined;
|
|
128
168
|
return validateInitAnswers({ platform, ...(id ? { appId: id } : {}), ...(webUrl ? { url: webUrl } : {}) });
|
|
129
169
|
}
|
|
@@ -141,6 +181,21 @@ async function whoamiCommand() {
|
|
|
141
181
|
process.stdout.write(`Signed in to Revyl as ${name}${org ? ` in ${org}` : ''} (credentials from ${credentials.source}).\n`);
|
|
142
182
|
return 0;
|
|
143
183
|
}
|
|
184
|
+
async function logoutCommand() {
|
|
185
|
+
try {
|
|
186
|
+
await rm(revylCredentialsPath());
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (error.code !== 'ENOENT')
|
|
190
|
+
throw new VerifyError('AUTH_MISSING', `Could not remove ~/.revyl/credentials.json: ${errorMessage(error)}`);
|
|
191
|
+
process.stdout.write('No saved Revyl login on this computer.\n');
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
process.stdout.write('Signed out: removed ~/.revyl/credentials.json, which the Revyl CLI shares. The API key it held still works until you delete it in Revyl (Settings → API keys).\n');
|
|
195
|
+
if (process.env.REVYL_API_KEY?.trim())
|
|
196
|
+
process.stdout.write('REVYL_API_KEY is still set in this environment, so Verify keeps using it.\n');
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
144
199
|
export async function runCli(argv) {
|
|
145
200
|
const [major = 0, minor = 0] = process.versions.node.split('.').map(Number);
|
|
146
201
|
if (major < 22 || (major === 22 && minor < 18)) {
|
|
@@ -27,6 +27,15 @@ export declare class ComputerSession implements Session {
|
|
|
27
27
|
open(target: HostedTargetConfig): Promise<OpenedSession>;
|
|
28
28
|
report(): Promise<Record<string, unknown>>;
|
|
29
29
|
navigate(): Promise<never>;
|
|
30
|
+
tap(): Promise<never>;
|
|
31
|
+
type(): Promise<never>;
|
|
32
|
+
swipe(): Promise<never>;
|
|
33
|
+
pressKey(): Promise<never>;
|
|
34
|
+
back(): Promise<never>;
|
|
35
|
+
openUrl(): Promise<never>;
|
|
36
|
+
launchApp(): Promise<never>;
|
|
37
|
+
locate(): Promise<never>;
|
|
38
|
+
screenSize(): Promise<never>;
|
|
30
39
|
get expiresAt(): Date | undefined;
|
|
31
40
|
recording(): Promise<ComputerRecording | null>;
|
|
32
41
|
instruction(): Promise<never>;
|
package/dist/computer-session.js
CHANGED
|
@@ -123,6 +123,33 @@ export class ComputerSession {
|
|
|
123
123
|
navigate() {
|
|
124
124
|
return this.unavailable('navigate');
|
|
125
125
|
}
|
|
126
|
+
tap() {
|
|
127
|
+
return this.unavailable('tap');
|
|
128
|
+
}
|
|
129
|
+
type() {
|
|
130
|
+
return this.unavailable('type');
|
|
131
|
+
}
|
|
132
|
+
swipe() {
|
|
133
|
+
return this.unavailable('swipe');
|
|
134
|
+
}
|
|
135
|
+
pressKey() {
|
|
136
|
+
return this.unavailable('pressKey');
|
|
137
|
+
}
|
|
138
|
+
back() {
|
|
139
|
+
return this.unavailable('back');
|
|
140
|
+
}
|
|
141
|
+
openUrl() {
|
|
142
|
+
return this.unavailable('openUrl');
|
|
143
|
+
}
|
|
144
|
+
launchApp() {
|
|
145
|
+
return this.unavailable('launchApp');
|
|
146
|
+
}
|
|
147
|
+
locate() {
|
|
148
|
+
return this.unavailable('locate');
|
|
149
|
+
}
|
|
150
|
+
screenSize() {
|
|
151
|
+
return this.unavailable('screenSize');
|
|
152
|
+
}
|
|
126
153
|
get expiresAt() {
|
|
127
154
|
return this.expiresAtMs === undefined ? undefined : new Date(this.expiresAtMs);
|
|
128
155
|
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type VerifyErrorCode = 'INVALID_ARGUMENT' | 'CONFIG_NOT_FOUND' | 'CONFIG_INVALID' | 'AUTH_MISSING' | 'COMPUTER_ID_MISSING' | 'AUTH_REJECTED' | 'EDGE_BLOCKED' | 'API_ERROR' | 'SESSION_START_FAILED' | 'SESSION_ENDED' | 'SESSION_BUSY' | 'COMPUTER_LIMIT' | 'NOT_AVAILABLE_ON_PLATFORM' | 'ACTION_FAILED' | 'ACTION_UNCERTAIN' | 'INSTRUCTION_FAILED' | 'VALIDATION_FAILED' | 'STEP_FAILED' | 'COMMAND_FAILED' | 'NOT_FOUND' | 'ACCESS_DENIED' | 'TIMEOUT';
|
|
2
|
-
export type RefusalReason = 'web_runtime_unavailable' | 'web_runtime_not_configured' | 'computer_limit' | 'runtime_unavailable' | 'computer_runtime_unavailable' | 'computer_at_capacity' | 'computer_not_running' | 'computer_cannot_host_platform' | 'computer_not_found' | 'web_build_required' | 'web_build_not_supported' | 'ios_build_required' | 'ios_build_not_supported' | 'android_build_required' | 'android_build_not_supported' | 'web_session_conflict' | 'ios_session_conflict' | 'android_session_conflict' | 'not_available_on_platform' | 'request_timeout' | 'protocol_error';
|
|
1
|
+
export type VerifyErrorCode = 'INVALID_ARGUMENT' | 'CONFIG_NOT_FOUND' | 'CONFIG_INVALID' | 'AUTH_MISSING' | 'COMPUTER_ID_MISSING' | 'AUTH_REJECTED' | 'EDGE_BLOCKED' | 'API_ERROR' | 'SESSION_START_FAILED' | 'SESSION_ENDED' | 'SESSION_BUSY' | 'COMPUTER_LIMIT' | 'NOT_AVAILABLE_ON_PLATFORM' | 'ACTION_FAILED' | 'ACTION_UNCERTAIN' | 'INSTRUCTION_FAILED' | 'VALIDATION_FAILED' | 'STEP_FAILED' | 'COMMAND_FAILED' | 'NOT_FOUND' | 'ACCESS_DENIED' | 'MODEL_ERROR' | 'MODEL_KEY_MISSING' | 'TIMEOUT';
|
|
2
|
+
export type RefusalReason = 'web_runtime_unavailable' | 'web_runtime_not_configured' | 'computer_limit' | 'runtime_unavailable' | 'computer_runtime_unavailable' | 'computer_at_capacity' | 'computer_platform_at_capacity' | 'computer_not_running' | 'computer_cannot_host_platform' | 'computer_not_found' | 'web_build_required' | 'web_build_not_supported' | 'ios_build_required' | 'ios_build_not_supported' | 'android_build_required' | 'android_build_not_supported' | 'web_session_conflict' | 'ios_session_conflict' | 'android_session_conflict' | 'not_available_on_platform' | 'request_timeout' | 'protocol_error';
|
|
3
3
|
export declare class VerifyError extends Error {
|
|
4
4
|
readonly code: VerifyErrorCode;
|
|
5
5
|
readonly reason?: RefusalReason;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,3 +6,8 @@ export type { HostedTargetConfig, MobileAppConfig, MobileTargetConfig, ComputerT
|
|
|
6
6
|
export type { Platform, ComputerPlatform, MobilePlatform } from './api/types.js';
|
|
7
7
|
export { VerifyError, isVerifyError } from './errors.js';
|
|
8
8
|
export type { RefusalReason, VerifyErrorCode } from './errors.js';
|
|
9
|
+
export { localAgent } from './agent/loop.js';
|
|
10
|
+
export type { Grounding, LocalAgent, LocalAgentOptions, Location, ModelRun, ModelTurn, Point, SwipeDirection, Target } from './agent/loop.js';
|
|
11
|
+
export type { CustomModel, ModelOption } from './agent/providers.js';
|
|
12
|
+
export { anthropic, openaiCompatible } from './agent/model.js';
|
|
13
|
+
export type { AnthropicOptions, JsonSchema, ModelAdapter, ModelReply, ModelRequest, ModelTool, ModelToolCall, ModelUsage, OpenAICompatibleOptions } from './agent/model.js';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { attach, currentComputer, open } from './open.js';
|
|
2
2
|
export { defineConfig } from './config.js';
|
|
3
3
|
export { VerifyError, isVerifyError } from './errors.js';
|
|
4
|
+
export { localAgent } from './agent/loop.js';
|
|
5
|
+
export { anthropic, openaiCompatible } from './agent/model.js';
|
package/dist/open.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type TargetConfig } from './config.js';
|
|
2
2
|
import { type OpenedSession } from './session.js';
|
|
3
3
|
import { ComputerSession } from './computer-session.js';
|
|
4
|
+
import type { LocalAgent } from './agent/loop.js';
|
|
5
|
+
import { type ModelOption } from './agent/providers.js';
|
|
4
6
|
export interface OpenOptions {
|
|
5
7
|
/** The config file to read target names from. Defaults to the nearest verify.config.ts at or above the current folder. */
|
|
6
8
|
config?: string;
|
|
@@ -8,6 +10,10 @@ export interface OpenOptions {
|
|
|
8
10
|
log?: false | ((line: string) => void);
|
|
9
11
|
backendUrl?: string;
|
|
10
12
|
appUrl?: string;
|
|
13
|
+
/** Runs every instruction and validation on your model, such as 'anthropic/claude-sonnet-5-5', instead of Revyl's agent. Browsers and devices only. */
|
|
14
|
+
model?: ModelOption;
|
|
15
|
+
/** Runs every instruction and validation on a custom agent from localAgent(). Pass model or agent, not both. */
|
|
16
|
+
agent?: LocalAgent;
|
|
11
17
|
}
|
|
12
18
|
export interface AttachOptions extends Pick<OpenOptions, 'log' | 'backendUrl' | 'appUrl'> {
|
|
13
19
|
stopOnClose?: boolean;
|
package/dist/open.js
CHANGED
|
@@ -5,6 +5,7 @@ import { DEFAULT_STEP_TIMEOUT_MS, loadConfig, validateTarget } from './config.js
|
|
|
5
5
|
import { VerifyError } from './errors.js';
|
|
6
6
|
import { DeviceSession } from './session.js';
|
|
7
7
|
import { ComputerSession } from './computer-session.js';
|
|
8
|
+
import { chooseAgent } from './agent/providers.js';
|
|
8
9
|
const signIns = new Map();
|
|
9
10
|
async function credentialsForUse(options) {
|
|
10
11
|
const credentials = await resolveCredentials();
|
|
@@ -53,10 +54,14 @@ export async function open(target, options = {}) {
|
|
|
53
54
|
else {
|
|
54
55
|
resolved = validateTarget(target);
|
|
55
56
|
}
|
|
57
|
+
const agent = chooseAgent(options, 'open()');
|
|
58
|
+
if (agent && (resolved.platform === 'mac' || resolved.platform === 'linux')) {
|
|
59
|
+
throw new VerifyError('NOT_AVAILABLE_ON_PLATFORM', 'Your own model runs steps on browsers and devices, not on computers.');
|
|
60
|
+
}
|
|
56
61
|
const credentials = await credentialsForUse(options);
|
|
57
62
|
const log = options.log === false ? undefined : (options.log ?? ((line) => void process.stderr.write(`[verify] ${line}\n`)));
|
|
58
63
|
const client = new RevylClient({ token: credentials.token, backendUrl: options.backendUrl });
|
|
59
64
|
if (resolved.platform === 'mac' || resolved.platform === 'linux')
|
|
60
65
|
return ComputerSession.start(client, resolved, { stepTimeout, log, appUrl: options.appUrl });
|
|
61
|
-
return DeviceSession.start(client, resolved, { stepTimeout, log, appUrl: options.appUrl });
|
|
66
|
+
return DeviceSession.start(client, resolved, { stepTimeout, log, appUrl: options.appUrl, ...(agent ? { agent } : {}) });
|
|
62
67
|
}
|
package/dist/session.d.ts
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import { RevylClient } from './api/client.js';
|
|
2
2
|
import type { LiveStepType, Platform } from './api/types.js';
|
|
3
3
|
import type { HostedTargetConfig, ResolvedDeviceTarget } from './config.js';
|
|
4
|
+
import { type LocalAgent, type Location, type ModelRun, type Point, type SwipeDirection } from './agent/loop.js';
|
|
5
|
+
import { type ModelOption } from './agent/providers.js';
|
|
4
6
|
export type StepType = LiveStepType;
|
|
5
7
|
/** The outcome of one instruction or validation, as Revyl's agent reported it. */
|
|
6
8
|
export interface StepResult {
|
|
7
9
|
type: StepType;
|
|
8
10
|
text: string;
|
|
9
11
|
passed: boolean;
|
|
10
|
-
/** Revyl's explanation, when
|
|
12
|
+
/** Revyl's explanation, or your model's when the step ran on a local agent. */
|
|
11
13
|
reason?: string;
|
|
12
14
|
durationMs: number;
|
|
15
|
+
/** Present when the step ran on your model: its name, grounding, turns and token use. */
|
|
16
|
+
model?: ModelRun;
|
|
13
17
|
}
|
|
14
18
|
export interface StepOptions {
|
|
15
|
-
/** Milliseconds before the step is cancelled
|
|
19
|
+
/** Milliseconds before the step is cancelled. Defaults to stepTimeout from the config, or 180000. */
|
|
16
20
|
timeout?: number;
|
|
21
|
+
/** Runs this step on your model, such as 'anthropic/claude-sonnet-5-5', instead of Revyl's agent. Overrides the model passed to open(). */
|
|
22
|
+
model?: ModelOption;
|
|
23
|
+
/** Runs this step on a custom agent from localAgent(). Overrides the one passed to open(); pass model or agent, not both. */
|
|
24
|
+
agent?: LocalAgent;
|
|
17
25
|
}
|
|
18
26
|
export interface ValidationOptions extends StepOptions {
|
|
19
27
|
/** Return a failed result instead of throwing VALIDATION_FAILED. */
|
|
@@ -95,11 +103,37 @@ export interface OpenedSession extends Session {
|
|
|
95
103
|
report(): Promise<Record<string, unknown>>;
|
|
96
104
|
navigate(url: string): Promise<void>;
|
|
97
105
|
open(target: HostedTargetConfig): Promise<OpenedSession>;
|
|
106
|
+
/** Taps a point in device units, or an element Revyl locates from a description. Returns the point tapped. Browsers and devices only. */
|
|
107
|
+
tap(at: Location): Promise<Point>;
|
|
108
|
+
/** Taps a text field and types into it, clearing it first unless clear is false. Returns the point tapped. Browsers and devices only. */
|
|
109
|
+
type(at: Location, text: string, options?: {
|
|
110
|
+
clear?: boolean;
|
|
111
|
+
}): Promise<Point>;
|
|
112
|
+
/** Swipes from a point or the screen's center. 'up' moves the finger up, which scrolls content down. Browsers and devices only. */
|
|
113
|
+
swipe(direction: SwipeDirection, options?: {
|
|
114
|
+
from?: Location;
|
|
115
|
+
}): Promise<void>;
|
|
116
|
+
/** Presses Enter or Backspace on the focused field. Browsers and devices only. */
|
|
117
|
+
pressKey(key: 'enter' | 'backspace'): Promise<void>;
|
|
118
|
+
/** Goes back: browser history on Web, the back button on Android. Not on iOS. */
|
|
119
|
+
back(): Promise<void>;
|
|
120
|
+
/** Opens a URL or deep link on a device, or loads a URL in a browser. */
|
|
121
|
+
openUrl(url: string): Promise<void>;
|
|
122
|
+
/** Launches an installed app by bundle ID or package name. Devices only. */
|
|
123
|
+
launchApp(bundleId: string): Promise<void>;
|
|
124
|
+
/** Asks Revyl's grounding model where an element is on the current screen, in device units. Browsers and devices only. */
|
|
125
|
+
locate(target: string): Promise<Point>;
|
|
126
|
+
/** The screen size in device units: iOS points, Android and Web pixels. Browsers and devices only. */
|
|
127
|
+
screenSize(): Promise<{
|
|
128
|
+
width: number;
|
|
129
|
+
height: number;
|
|
130
|
+
}>;
|
|
98
131
|
}
|
|
99
132
|
export interface SessionOptions {
|
|
100
133
|
stepTimeout: number;
|
|
101
134
|
log: ((line: string) => void) | undefined;
|
|
102
135
|
appUrl?: string;
|
|
136
|
+
agent?: LocalAgent;
|
|
103
137
|
}
|
|
104
138
|
export interface HostingParent {
|
|
105
139
|
id: string;
|
|
@@ -125,6 +159,8 @@ export declare class DeviceSession implements Session {
|
|
|
125
159
|
private stepRunning;
|
|
126
160
|
private parent?;
|
|
127
161
|
private readySignal?;
|
|
162
|
+
private size?;
|
|
163
|
+
private attribution?;
|
|
128
164
|
get expiresAt(): Date | undefined;
|
|
129
165
|
private constructor();
|
|
130
166
|
static start(client: RevylClient, target: ResolvedDeviceTarget, options: SessionOptions, parent?: HostingParent): Promise<DeviceSession>;
|
|
@@ -143,6 +179,7 @@ export declare class DeviceSession implements Session {
|
|
|
143
179
|
}): Promise<Uint8Array>;
|
|
144
180
|
report(): Promise<Record<string, unknown>>;
|
|
145
181
|
navigate(url: string): Promise<void>;
|
|
182
|
+
private navigateTo;
|
|
146
183
|
exec(): Promise<ExecResult>;
|
|
147
184
|
open(): Promise<never>;
|
|
148
185
|
recording(): Promise<never>;
|
|
@@ -156,6 +193,38 @@ export declare class DeviceSession implements Session {
|
|
|
156
193
|
[Symbol.asyncDispose](): Promise<void>;
|
|
157
194
|
private step;
|
|
158
195
|
private runStep;
|
|
196
|
+
private runLocal;
|
|
197
|
+
private agentControls;
|
|
198
|
+
/** Taps a point in device units, or an element Revyl locates from a description. Returns the point tapped. */
|
|
199
|
+
tap(at: Location): Promise<Point>;
|
|
200
|
+
/** Taps a text field and types into it, clearing it first unless clear is false. Returns the point tapped. */
|
|
201
|
+
type(at: Location, text: string, options?: {
|
|
202
|
+
clear?: boolean;
|
|
203
|
+
}): Promise<Point>;
|
|
204
|
+
/** Swipes from a point or the screen's center. 'up' moves the finger up, which scrolls content down. */
|
|
205
|
+
swipe(direction: SwipeDirection, options?: {
|
|
206
|
+
from?: Location;
|
|
207
|
+
}): Promise<void>;
|
|
208
|
+
/** Presses Enter or Backspace on the focused field. */
|
|
209
|
+
pressKey(key: 'enter' | 'backspace'): Promise<void>;
|
|
210
|
+
/** Goes back: browser history on Web, the back button on Android. Not on iOS. */
|
|
211
|
+
back(): Promise<void>;
|
|
212
|
+
/** Opens a URL or deep link on a device, or loads a URL in a browser. */
|
|
213
|
+
openUrl(url: string): Promise<void>;
|
|
214
|
+
/** Launches an installed app by bundle ID or package name. Devices only. */
|
|
215
|
+
launchApp(bundleId: string): Promise<void>;
|
|
216
|
+
/** Asks Revyl's grounding model where an element is on the current screen, in device units. */
|
|
217
|
+
locate(target: string): Promise<Point>;
|
|
218
|
+
/** The screen size in device units: iOS points, Android and Web pixels. */
|
|
219
|
+
screenSize(): Promise<{
|
|
220
|
+
width: number;
|
|
221
|
+
height: number;
|
|
222
|
+
}>;
|
|
223
|
+
private readScreenSize;
|
|
224
|
+
private capture;
|
|
225
|
+
private perform;
|
|
226
|
+
private resolve;
|
|
227
|
+
private act;
|
|
159
228
|
private launch;
|
|
160
229
|
private waitForScreenContent;
|
|
161
230
|
private log;
|