@e2edev/agent-device 0.1.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/backend.d.ts +16 -0
  4. package/dist/backend.d.ts.map +1 -0
  5. package/dist/backend.js +66 -0
  6. package/dist/backend.js.map +1 -0
  7. package/dist/device.d.ts +69 -0
  8. package/dist/device.d.ts.map +1 -0
  9. package/dist/device.js +77 -0
  10. package/dist/device.js.map +1 -0
  11. package/dist/errors.d.ts +25 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +72 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/index.d.ts +18 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +14 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/locate.d.ts +14 -0
  20. package/dist/locate.d.ts.map +1 -0
  21. package/dist/locate.js +100 -0
  22. package/dist/locate.js.map +1 -0
  23. package/dist/nodes.d.ts +82 -0
  24. package/dist/nodes.d.ts.map +1 -0
  25. package/dist/nodes.js +295 -0
  26. package/dist/nodes.js.map +1 -0
  27. package/dist/png.d.ts +22 -0
  28. package/dist/png.d.ts.map +1 -0
  29. package/dist/png.js +172 -0
  30. package/dist/png.js.map +1 -0
  31. package/dist/selector.d.ts +17 -0
  32. package/dist/selector.d.ts.map +1 -0
  33. package/dist/selector.js +84 -0
  34. package/dist/selector.js.map +1 -0
  35. package/dist/support.d.ts +59 -0
  36. package/dist/support.d.ts.map +1 -0
  37. package/dist/support.js +105 -0
  38. package/dist/support.js.map +1 -0
  39. package/dist/surface.d.ts +146 -0
  40. package/dist/surface.d.ts.map +1 -0
  41. package/dist/surface.js +485 -0
  42. package/dist/surface.js.map +1 -0
  43. package/dist/tools.d.ts +24 -0
  44. package/dist/tools.d.ts.map +1 -0
  45. package/dist/tools.js +110 -0
  46. package/dist/tools.js.map +1 -0
  47. package/package.json +80 -0
@@ -0,0 +1,485 @@
1
+ /**
2
+ * The agent-device surface: one simulator or emulator session, driven through
3
+ * agent-device's typed client, exposed to the runner as the contract's
4
+ * observe/locate/perform members. It owns the id space (one fresh generation
5
+ * per observation), the attempt state (artifact directory, screenshot
6
+ * counter), and every translation between the contract's vocabulary and
7
+ * agent-device's commands. The runner owns everything else.
8
+ */
9
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
10
+ import { tmpdir } from 'node:os';
11
+ import path from 'node:path';
12
+ import { BackendError, } from '@e2edev/e2e/backend';
13
+ import { staleOr, translateError } from './errors.js';
14
+ import { resolveExpression } from './locate.js';
15
+ import { isWithin, projectSnapshot, screenTitle } from './nodes.js';
16
+ import { maskPng } from './png.js';
17
+ import { invalidState, notActionable, raceAbort, readPngSize, sanitizeFilename, screenUrl, swipeWithin, unsupported, withinCleanupBudget, } from './support.js';
18
+ /**
19
+ * The Apple runner defers a full snapshot after slow accessibility work and
20
+ * returns a sparse one-node tree. Retrying device-side costs under a second;
21
+ * returning the sparse tree costs the model a confused turn.
22
+ */
23
+ const SPARSE_RETRY_BACKOFF_MS = [0, 1_200, 3_000];
24
+ /** Number of parent hops from `entry` up to `ancestor`. */
25
+ function depthBelow(entry, ancestor) {
26
+ let hops = 0;
27
+ for (let current = entry.parent; current !== undefined; current = current.parent) {
28
+ hops += 1;
29
+ if (current === ancestor)
30
+ return hops;
31
+ }
32
+ return hops;
33
+ }
34
+ function sleep(ms, signal) {
35
+ return new Promise((resolve) => {
36
+ const timer = setTimeout(done, ms);
37
+ function done() {
38
+ clearTimeout(timer);
39
+ signal.removeEventListener('abort', done);
40
+ resolve();
41
+ }
42
+ signal.addEventListener('abort', done, { once: true });
43
+ });
44
+ }
45
+ export class AgentDeviceSurface {
46
+ options;
47
+ createClient;
48
+ client;
49
+ testIdAttribute = 'data-testid';
50
+ attempt;
51
+ generation = new Map();
52
+ idCounter = 0;
53
+ appIdentity;
54
+ /**
55
+ * Commands still running on the device. agent-device takes no abort
56
+ * signal, so a cancelled or timed-out call is only abandoned by its
57
+ * caller; it keeps executing. The next attempt waits for these to settle
58
+ * before it opens anything, so a ghost tap can never land in a retry.
59
+ */
60
+ inflight = new Set();
61
+ constructor(options, createClient) {
62
+ this.options = options;
63
+ this.createClient = createClient;
64
+ }
65
+ /** Whether the manifest declares app restart and state clearing. */
66
+ get managesApp() {
67
+ return this.options.app !== undefined;
68
+ }
69
+ /** Whether an attempt is running on this surface right now. */
70
+ get attemptRunning() {
71
+ return this.attempt !== undefined;
72
+ }
73
+ /** The live client; INVALID_STATE before init or after dispose. */
74
+ requireClient() {
75
+ if (this.client === undefined)
76
+ throw invalidState('the agent-device backend is not initialized');
77
+ return this.client;
78
+ }
79
+ /**
80
+ * Runs one agent-device command under an operation budget and translates
81
+ * its failure. Contributed-fixture methods route through here too, so the
82
+ * device fixture never carries its own error mapping.
83
+ */
84
+ async command(label, run, signal) {
85
+ const client = this.requireClient();
86
+ try {
87
+ const pending = this.track(run(client));
88
+ return await (signal === undefined ? pending : raceAbort(pending, signal, label));
89
+ }
90
+ catch (cause) {
91
+ throw translateError(cause, label);
92
+ }
93
+ }
94
+ /** Registers one device command as in flight until it settles. */
95
+ track(pending) {
96
+ this.inflight.add(pending);
97
+ pending.then(() => this.inflight.delete(pending), () => this.inflight.delete(pending));
98
+ return pending;
99
+ }
100
+ /**
101
+ * Waits for every abandoned command to settle, within the caller's
102
+ * budget. A command that never settles fails the attempt launch instead of
103
+ * racing it: the launch timeout is the honest bound on a stuck device.
104
+ */
105
+ async settleInflight(signal) {
106
+ while (this.inflight.size > 0) {
107
+ await raceAbort(Promise.allSettled(this.inflight), signal, 'settling in-flight device commands');
108
+ }
109
+ }
110
+ async init(info) {
111
+ this.testIdAttribute = info.testIdAttribute;
112
+ this.client ??= this.createClient(this.options.session ?? `e2e-${info.targetName}`);
113
+ await this.command('boot', (client) => client.devices.boot({
114
+ platform: this.options.platform,
115
+ ...(this.options.device === undefined ? {} : { device: this.options.device }),
116
+ }), info.signal);
117
+ }
118
+ async startAttempt(context) {
119
+ if (this.attempt !== undefined) {
120
+ throw invalidState('an attempt is already running on this agent-device backend');
121
+ }
122
+ await this.settleInflight(context.signal);
123
+ this.attempt = { artifactsDir: context.artifactsDir, screenshots: 0 };
124
+ this.generation = new Map();
125
+ if (this.options.app === undefined)
126
+ return;
127
+ await this.openApp(this.options.app, true, context.signal);
128
+ }
129
+ async endAttempt(_context) {
130
+ this.attempt = undefined;
131
+ this.generation = new Map();
132
+ }
133
+ async dispose(context) {
134
+ const client = this.client;
135
+ this.client = undefined;
136
+ this.attempt = undefined;
137
+ this.generation = new Map();
138
+ this.appIdentity = undefined;
139
+ if (client === undefined)
140
+ return;
141
+ await withinCleanupBudget(client.sessions.close().catch(() => undefined), context);
142
+ }
143
+ /** Opens an app in the session, remembering its identity for the path anchor. */
144
+ async openApp(app, relaunch, signal) {
145
+ const result = await this.command(`open ${app}`, (client) => client.apps.open({
146
+ app,
147
+ platform: this.options.platform,
148
+ ...(this.options.device === undefined ? {} : { device: this.options.device }),
149
+ ...(relaunch ? { relaunch: true } : {}),
150
+ }), signal);
151
+ this.appIdentity = result.appBundleId ?? result.appName ?? app;
152
+ this.generation = new Map();
153
+ }
154
+ async snapshot(operation, interactiveOnly) {
155
+ let last = {};
156
+ for (const backoffMs of SPARSE_RETRY_BACKOFF_MS) {
157
+ if (backoffMs > 0)
158
+ await sleep(backoffMs, operation.signal);
159
+ if (operation.signal.aborted)
160
+ throw new BackendError('CANCELLED', 'snapshot cancelled', { retryable: false });
161
+ last = (await this.command('snapshot', (client) => client.capture.snapshot({ interactiveOnly }), operation.signal));
162
+ if (last.appBundleId !== undefined || last.appName !== undefined) {
163
+ this.appIdentity = last.appBundleId ?? last.appName;
164
+ }
165
+ if (last.snapshotQuality?.state !== 'sparse')
166
+ return last;
167
+ }
168
+ return last;
169
+ }
170
+ /**
171
+ * Snapshot for an observation. Without a pinned app, an observation before
172
+ * anything is open is an empty screen rather than a fault: the model's next
173
+ * move is the open tool, and failing the step would take that move away.
174
+ */
175
+ async snapshotOrEmpty(operation, interactiveOnly) {
176
+ try {
177
+ return await this.snapshot(operation, interactiveOnly);
178
+ }
179
+ catch (cause) {
180
+ if (!this.managesApp && cause instanceof BackendError && cause.code === 'INVALID_STATE')
181
+ return { nodes: [] };
182
+ throw cause;
183
+ }
184
+ }
185
+ project(raw) {
186
+ return projectSnapshot(raw.nodes ?? [], {
187
+ testIdAttribute: this.testIdAttribute,
188
+ mintId: () => {
189
+ this.idCounter += 1;
190
+ return `n${this.idCounter}`;
191
+ },
192
+ });
193
+ }
194
+ async observe(operation, options) {
195
+ const raw = await this.snapshotOrEmpty(operation, this.options.snapshot === 'interactive');
196
+ const projected = this.project(raw);
197
+ this.generation = new Map(projected.index.map((entry) => [entry.id, entry]));
198
+ const capture = options?.pixels === true ? await this.capturePixels(operation, projected) : undefined;
199
+ return {
200
+ nodes: projected.roots,
201
+ ...(projected.viewport === undefined ? {} : { viewport: projected.viewport }),
202
+ ...(capture === undefined ? {} : { pixels: capture.pixels, maskedRegionCount: capture.masked }),
203
+ };
204
+ }
205
+ /**
206
+ * The located snapshot joins the current generation instead of replacing
207
+ * it, so an observation's ids stay valid across a `screen` query in the
208
+ * same step. The whole snapshot joins, not only the matches: a later action
209
+ * on a match may need its descendants (`controlOf`).
210
+ */
211
+ async locate(expression, operation) {
212
+ const raw = await this.snapshotOrEmpty(operation, false);
213
+ const projected = this.project(raw);
214
+ const matches = resolveExpression(expression, projected.index, { testIdAttribute: this.testIdAttribute });
215
+ for (const entry of projected.index)
216
+ this.generation.set(entry.id, entry);
217
+ return matches.map((entry) => entry.node);
218
+ }
219
+ resolveRef(ref) {
220
+ const entry = this.generation.get(ref.id);
221
+ if (entry === undefined) {
222
+ throw new BackendError('NODE_STALE', `node ${ref.id} is not part of the newest observation`, { retryable: true });
223
+ }
224
+ return entry;
225
+ }
226
+ actionTarget(entry) {
227
+ if (entry.ref === '')
228
+ throw notActionable(`node ${entry.id} has no agent-device ref to act on`);
229
+ return { ref: `@${entry.ref}` };
230
+ }
231
+ /**
232
+ * The node a toggle press must land on. UIKit reports a settings row as a
233
+ * labelled `Switch` spanning the whole row with the real control as an
234
+ * unlabelled `Switch` child at its trailing edge; a press at the row's
235
+ * centre hits the label and changes nothing. The innermost same-role
236
+ * descendant with a ref is the control; a node without one is its own.
237
+ */
238
+ controlOf(entry) {
239
+ const role = entry.node.role;
240
+ if (role !== 'switch' && role !== 'checkbox')
241
+ return entry;
242
+ let control = entry;
243
+ let depth = 0;
244
+ for (const candidate of this.generation.values()) {
245
+ if (candidate.ref === '' || candidate.node.role !== role || !isWithin(candidate, entry))
246
+ continue;
247
+ const candidateDepth = depthBelow(candidate, entry);
248
+ if (candidateDepth > depth) {
249
+ control = candidate;
250
+ depth = candidateDepth;
251
+ }
252
+ }
253
+ return control;
254
+ }
255
+ async perform(ref, action, operation) {
256
+ const entry = this.resolveRef(ref);
257
+ const label = `perform ${action.kind}`;
258
+ const client = this.requireClient();
259
+ const run = async () => {
260
+ switch (action.kind) {
261
+ // `settle` waits for the UI to go quiet after the input lands, so the
262
+ // observation that follows describes the screen the action produced,
263
+ // not a frame of its transition. Best-effort on agent-device's side.
264
+ case 'tap':
265
+ return client.interactions.press({ ...this.actionTarget(this.controlOf(entry)), settle: true });
266
+ case 'focus':
267
+ // A touch surface focuses by tapping, and a tap on anything but an
268
+ // editable field activates it; focus is offered for fields only.
269
+ if (entry.node.role !== 'textbox') {
270
+ throw unsupported(`agent-device can only focus editable fields; node ${entry.id} is ${entry.node.role ?? 'unknown'}`);
271
+ }
272
+ return client.interactions.press({ ...this.actionTarget(entry), settle: true });
273
+ case 'doubleTap':
274
+ return client.interactions.press({ ...this.actionTarget(entry), doubleTap: true, settle: true });
275
+ case 'longPress':
276
+ return client.interactions.longPress({
277
+ ...this.actionTarget(entry),
278
+ settle: true,
279
+ ...(action.durationMs === undefined ? {} : { durationMs: action.durationMs }),
280
+ });
281
+ case 'hover':
282
+ return client.interactions.hover(this.actionTarget(entry));
283
+ case 'fill':
284
+ // oxlint-disable-next-line unicorn/no-array-fill-with-reference-type -- agent-device fill, not Array#fill
285
+ return client.interactions.fill({ ...this.actionTarget(entry), text: action.value, settle: true });
286
+ case 'clear':
287
+ // oxlint-disable-next-line unicorn/no-array-fill-with-reference-type -- agent-device fill, not Array#fill
288
+ return client.interactions.fill({ ...this.actionTarget(entry), text: '', settle: true });
289
+ case 'check':
290
+ case 'uncheck': {
291
+ const wanted = action.kind === 'check';
292
+ const checked = entry.node.states?.checked;
293
+ // A toggle whose state the tree does not expose (Android switches)
294
+ // cannot be set, only flipped; flipping blind could undo a correct state.
295
+ if (checked === undefined) {
296
+ throw unsupported(`agent-device cannot read whether node ${entry.id} is checked; tap it instead`);
297
+ }
298
+ if (checked === wanted)
299
+ return undefined;
300
+ return client.interactions.press({ ...this.actionTarget(this.controlOf(entry)), settle: true });
301
+ }
302
+ case 'press':
303
+ return this.pressKey(client, entry, action.key);
304
+ case 'swipe': {
305
+ const rect = entry.node.rect;
306
+ if (rect === undefined)
307
+ throw notActionable(`node ${entry.id} has no bounds to swipe within`);
308
+ return client.interactions.swipe(swipeWithin(rect, action.direction, action.momentum));
309
+ }
310
+ case 'dragTo': {
311
+ const destination = this.resolveRef(action.target);
312
+ return client.interactions.drag({
313
+ source: this.actionTarget(entry).ref,
314
+ destination: this.actionTarget(destination).ref,
315
+ });
316
+ }
317
+ case 'scrollIntoView':
318
+ case 'selectOption':
319
+ case 'setInputFiles':
320
+ throw unsupported(`agent-device cannot perform "${action.kind}" on a device surface`);
321
+ }
322
+ };
323
+ try {
324
+ await raceAbort(this.track(run()), operation.signal, label);
325
+ }
326
+ catch (cause) {
327
+ throw staleOr(cause, label);
328
+ }
329
+ }
330
+ /**
331
+ * Keys on a touch surface: Enter submits through the soft keyboard, a
332
+ * single character is typed into the focused field; there is no key event
333
+ * bus to send `Escape` or `Tab` to.
334
+ */
335
+ async pressKey(client, entry, key) {
336
+ if (key === 'Enter' || key === 'Return') {
337
+ return client.command.keyboard({ action: 'enter' });
338
+ }
339
+ if ([...key].length === 1) {
340
+ if (entry.node.role === 'textbox' && entry.node.states?.focused !== true) {
341
+ await client.interactions.press({ ...this.actionTarget(entry), settle: true });
342
+ }
343
+ return client.interactions.type({ text: key });
344
+ }
345
+ throw unsupported(`agent-device cannot press "${key}" on a device surface; only Enter and single characters are supported`);
346
+ }
347
+ async swipe(direction, _momentum, operation) {
348
+ await this.command('swipe', (client) => client.interactions.scroll({ direction }), operation.signal);
349
+ }
350
+ async back(operation) {
351
+ await this.command('back', (client) => client.command.back({ settle: true }), operation.signal);
352
+ }
353
+ async restart(operation) {
354
+ if (this.options.app === undefined)
355
+ throw unsupported('app.restart needs the backend option `app`');
356
+ await this.openApp(this.options.app, true, operation.signal);
357
+ }
358
+ async clearState(operation) {
359
+ const app = this.options.app;
360
+ if (app === undefined)
361
+ throw unsupported('app.clearState needs the backend option `app`');
362
+ await this.command('clear app state', (client) => client.settings.update({ setting: 'clear-app-state', state: 'clear', app }), operation.signal);
363
+ await this.openApp(app, true, operation.signal);
364
+ }
365
+ /** The path anchor: `app://<app>/<screen title>`; see `screenUrl`. */
366
+ async url(operation) {
367
+ const raw = await this.snapshot(operation, false);
368
+ const projected = projectSnapshot(raw.nodes ?? [], { testIdAttribute: this.testIdAttribute, mintId: () => 'anchor' });
369
+ return screenUrl(raw.appBundleId ?? raw.appName ?? this.appIdentity, screenTitle(projected));
370
+ }
371
+ /**
372
+ * A redacted screenshot artifact. The device paints secure fields as dots,
373
+ * but the last typed character shows in clear, so every secure node's
374
+ * bounds are painted over before the file is kept. A secure node without
375
+ * bounds cannot be masked, and an image that cannot be redacted is not
376
+ * written at all.
377
+ */
378
+ async screenshot(label, operation) {
379
+ const attempt = this.attempt;
380
+ if (attempt === undefined)
381
+ throw invalidState('screenshot outside an attempt');
382
+ const masked = await this.maskedScreenshot(operation.signal);
383
+ attempt.screenshots += 1;
384
+ const name = `${String(attempt.screenshots).padStart(3, '0')}-${sanitizeFilename(label ?? 'screenshot')}.png`;
385
+ const relative = path.join('screenshots', name);
386
+ mkdirSync(path.join(attempt.artifactsDir, 'screenshots'), { recursive: true });
387
+ writeFileSync(path.join(attempt.artifactsDir, relative), masked.data);
388
+ return relative;
389
+ }
390
+ /** Redacted screen pixels as a PNG, for the agent's screenshot tool. */
391
+ async screenshotBytes(signal) {
392
+ return (await this.maskedScreenshot(signal)).data;
393
+ }
394
+ /** Raw device pixels; the caller owns redaction. */
395
+ async rawScreenshot(signal) {
396
+ const file = path.join(tmpdir(), `e2e-agent-device-${process.pid}-${Date.now()}.png`);
397
+ try {
398
+ const shot = await this.command('screenshot', (client) => client.capture.screenshot({ path: file }), signal);
399
+ return new Uint8Array(readFileSync(shot.path ?? file));
400
+ }
401
+ finally {
402
+ rmSync(file, { force: true });
403
+ }
404
+ }
405
+ /**
406
+ * Screenshot with every secure node on the current screen painted over.
407
+ * Observes first so the regions describe the screen the pixels show;
408
+ * throws when a secure field cannot be covered, because an image that may
409
+ * hold a credential must not leave the backend.
410
+ */
411
+ async maskedScreenshot(signal) {
412
+ const operation = {
413
+ signal: signal ?? new AbortController().signal,
414
+ timeoutMs: 30_000,
415
+ runId: '',
416
+ attemptId: '',
417
+ };
418
+ const projected = this.project(await this.snapshotOrEmpty(operation, false));
419
+ const data = await this.rawScreenshot(signal);
420
+ const masked = redactSecure(data, projected);
421
+ if (masked === undefined) {
422
+ throw new BackendError('BACKEND_FAILURE', 'a secure field on screen could not be masked; screenshot withheld', {
423
+ retryable: false,
424
+ });
425
+ }
426
+ return masked;
427
+ }
428
+ /**
429
+ * Viewport pixels for an observation. Best-effort: a screenshot that cannot
430
+ * be produced or redacted costs the observation its image, not the step.
431
+ */
432
+ async capturePixels(operation, projected) {
433
+ let raw;
434
+ try {
435
+ raw = await this.rawScreenshot(operation.signal);
436
+ }
437
+ catch {
438
+ return undefined;
439
+ }
440
+ const redacted = redactSecure(raw, projected);
441
+ if (redacted === undefined)
442
+ return undefined;
443
+ const size = readPngSize(redacted.data);
444
+ if (size === undefined)
445
+ return undefined;
446
+ const viewport = projected.viewport;
447
+ const scale = viewport !== undefined && viewport.width > 0 ? size.width / viewport.width : 1;
448
+ return {
449
+ pixels: { data: redacted.data, mediaType: 'image/png', width: size.width, height: size.height, scale },
450
+ masked: redacted.masked,
451
+ };
452
+ }
453
+ }
454
+ /**
455
+ * Paints every secure node's bounds black on a screenshot of the same
456
+ * screen. Returns the masked bytes and how many regions were covered, or
457
+ * undefined when a secure node has no bounds or the image format cannot be
458
+ * edited: the caller then withholds the image rather than ship one it could
459
+ * not prove redacted. Bounds are in logical points; the image may be at
460
+ * device scale, so they are scaled by the image-to-viewport ratio.
461
+ */
462
+ function redactSecure(data, projected) {
463
+ const secure = projected.index.filter((entry) => entry.node.states?.secure === true);
464
+ if (secure.length === 0)
465
+ return { data, masked: 0 };
466
+ const size = readPngSize(data);
467
+ if (size === undefined)
468
+ return undefined;
469
+ const viewport = projected.viewport;
470
+ const scale = viewport !== undefined && viewport.width > 0 ? size.width / viewport.width : 1;
471
+ const rects = [];
472
+ for (const entry of secure) {
473
+ const rect = entry.node.rect;
474
+ if (rect === undefined)
475
+ return undefined;
476
+ rects.push({ x: rect.x * scale, y: rect.y * scale, width: rect.width * scale, height: rect.height * scale });
477
+ }
478
+ try {
479
+ return { data: maskPng(data, rects), masked: rects.length };
480
+ }
481
+ catch {
482
+ return undefined;
483
+ }
484
+ }
485
+ //# sourceMappingURL=surface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Agent-side tools for device targets. Everything a model plans through
3
+ * beyond the grammar verbs the backend already unlocks (tap, type, scroll)
4
+ * lives here: opening another app, a free-form swipe, typing into the focused
5
+ * field, system alerts, and a look at the pixels when the accessibility tree
6
+ * is not enough. Each tool is scoped to the platforms of the backends it was
7
+ * built from, so a mixed suite never offers it on a browser.
8
+ */
9
+ import { type DefinedTool } from '@e2edev/e2e/agent';
10
+ import { type BackendHandle } from '@e2edev/e2e/backend';
11
+ /**
12
+ * Builds the tool pack for one or more agent-device backends, keyed the way
13
+ * `createAgent({ tools })` expects. Pass every device backend a config
14
+ * declares: tool names are fixed, so two packs cannot be merged, and each
15
+ * tool is offered only on the platforms those backends drive. A worker runs
16
+ * one attempt at a time, so at execution the pack dispatches to the surface
17
+ * whose attempt is running.
18
+ *
19
+ * Mutating tools are recorded as replay gaps by the trace cache; a step that
20
+ * stays within the grammar verbs replays zero-turn, so prefer the backend's
21
+ * `app` option over `open_app` when a test always starts in the same app.
22
+ */
23
+ export declare function agentDeviceTools(...backends: readonly [BackendHandle, ...BackendHandle[]]): Readonly<Record<string, DefinedTool>>;
24
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAc,KAAK,WAAW,EAAwB,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAkBvE;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,QAAQ,EAAE,SAAS,CAAC,aAAa,EAAE,GAAG,aAAa,EAAE,CAAC,GACxD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAkGvC"}
package/dist/tools.js ADDED
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Agent-side tools for device targets. Everything a model plans through
3
+ * beyond the grammar verbs the backend already unlocks (tap, type, scroll)
4
+ * lives here: opening another app, a free-form swipe, typing into the focused
5
+ * field, system alerts, and a look at the pixels when the accessibility tree
6
+ * is not enough. Each tool is scoped to the platforms of the backends it was
7
+ * built from, so a mixed suite never offers it on a browser.
8
+ */
9
+ import { tool } from 'ai';
10
+ import { z } from 'zod';
11
+ import { defineTool } from '@e2edev/e2e/agent';
12
+ import { BackendError } from '@e2edev/e2e/backend';
13
+ import { surfaceOf } from './backend.js';
14
+ function requireSurface(backend) {
15
+ const surface = surfaceOf(backend);
16
+ if (surface === undefined) {
17
+ throw new BackendError('INVALID_STATE', 'agentDeviceTools needs handles returned by agentDevice()', {
18
+ retryable: false,
19
+ });
20
+ }
21
+ return surface;
22
+ }
23
+ /**
24
+ * Builds the tool pack for one or more agent-device backends, keyed the way
25
+ * `createAgent({ tools })` expects. Pass every device backend a config
26
+ * declares: tool names are fixed, so two packs cannot be merged, and each
27
+ * tool is offered only on the platforms those backends drive. A worker runs
28
+ * one attempt at a time, so at execution the pack dispatches to the surface
29
+ * whose attempt is running.
30
+ *
31
+ * Mutating tools are recorded as replay gaps by the trace cache; a step that
32
+ * stays within the grammar verbs replays zero-turn, so prefer the backend's
33
+ * `app` option over `open_app` when a test always starts in the same app.
34
+ */
35
+ export function agentDeviceTools(...backends) {
36
+ const surfaces = backends.map(requireSurface);
37
+ const platforms = [...new Set(surfaces.map((surface) => surface.options.platform))];
38
+ const active = () => {
39
+ const running = surfaces.filter((surface) => surface.attemptRunning);
40
+ const [surface] = running;
41
+ if (surface === undefined || running.length > 1) {
42
+ throw new BackendError('INVALID_STATE', running.length === 0
43
+ ? 'no agent-device attempt is running; device tools act inside a test attempt only'
44
+ : 'several agent-device attempts are running in one worker; tools cannot pick a device', { retryable: false });
45
+ }
46
+ return surface;
47
+ };
48
+ const annotate = (replay, mutates) => ({
49
+ replay,
50
+ mutates,
51
+ secrets: false,
52
+ platforms,
53
+ });
54
+ const abort = (options) => options.abortSignal;
55
+ return {
56
+ open_app: defineTool(tool({
57
+ description: 'Open an app by bundle id, package, or display name (e.g. "Settings"), bringing it to the foreground. Set relaunch to restart it fresh.',
58
+ inputSchema: z.object({ app: z.string().min(1), relaunch: z.boolean().optional() }),
59
+ execute: async ({ app, relaunch }, options) => {
60
+ await active().openApp(app, relaunch === true, abort(options) ?? new AbortController().signal);
61
+ return `Opened ${app}.`;
62
+ },
63
+ }), annotate('deterministic', true)),
64
+ swipe: defineTool(tool({
65
+ description: 'Swipe from one screen point to another in logical pixels, e.g. to reveal a row action (swipe the row far left) or to dismiss a sheet.',
66
+ inputSchema: z.object({
67
+ from: z.object({ x: z.number(), y: z.number() }),
68
+ to: z.object({ x: z.number(), y: z.number() }),
69
+ }),
70
+ execute: async ({ from, to }, options) => {
71
+ await active().command('swipe', (client) => client.interactions.swipe({ from, to }), abort(options));
72
+ return `Swiped from (${from.x}, ${from.y}) to (${to.x}, ${to.y}).`;
73
+ },
74
+ }), annotate('none', true)),
75
+ type_text: defineTool(tool({
76
+ description: 'Type text into whatever field currently has keyboard focus, then optionally press Return. Use only when the focused field is missing from the observation (some editors hide it); otherwise use the type verb on a node.',
77
+ inputSchema: z.object({ text: z.string().min(1), submit: z.boolean().optional() }),
78
+ execute: async ({ text, submit }, options) => {
79
+ const surface = active();
80
+ await surface.command('type', (client) => client.interactions.type({ text }), abort(options));
81
+ if (submit === true) {
82
+ await surface.command('keyboard', (client) => client.command.keyboard({ action: 'enter' }), abort(options));
83
+ }
84
+ return submit === true ? `Typed ${JSON.stringify(text)} and pressed Return.` : `Typed ${JSON.stringify(text)}.`;
85
+ },
86
+ }), annotate('none', true)),
87
+ alert: defineTool(tool({
88
+ description: 'Accept or dismiss a visible system alert or permission prompt.',
89
+ inputSchema: z.object({ action: z.enum(['accept', 'dismiss']) }),
90
+ execute: async ({ action }, options) => {
91
+ await active().command('alert', (client) => client.command.alert({ action }), abort(options));
92
+ return `Alert ${action}ed.`;
93
+ },
94
+ }), annotate('deterministic', true)),
95
+ screenshot: defineTool(tool({
96
+ description: 'Look at the actual screen pixels. Use when the observation tree is sparse or contradicts what you expect.',
97
+ inputSchema: z.object({}),
98
+ execute: async (_input, options) => {
99
+ const bytes = await active().screenshotBytes(abort(options));
100
+ return { png: Buffer.from(bytes).toString('base64') };
101
+ },
102
+ // The model gets the image itself, not a file path it cannot open.
103
+ toModelOutput: ({ output }) => ({
104
+ type: 'content',
105
+ value: [{ type: 'file', data: { type: 'data', data: output.png }, mediaType: 'image/png' }],
106
+ }),
107
+ }), annotate('none', false)),
108
+ };
109
+ }
110
+ //# sourceMappingURL=tools.js.map