@appilots/web-sdk 0.2.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/README.md +216 -0
- package/dist/AppilotsWebRuntime-DZF26UyU.d.mts +1389 -0
- package/dist/AppilotsWebRuntime-DZF26UyU.d.ts +1389 -0
- package/dist/chunk-T5TUFZ6T.js +10442 -0
- package/dist/chunk-VHRE4RUO.mjs +10382 -0
- package/dist/index.d.mts +1010 -0
- package/dist/index.d.ts +1010 -0
- package/dist/index.js +234 -0
- package/dist/index.mjs +1 -0
- package/dist/react/index.d.mts +84 -0
- package/dist/react/index.d.ts +84 -0
- package/dist/react/index.js +748 -0
- package/dist/react/index.mjs +738 -0
- package/package.json +76 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1010 @@
|
|
|
1
|
+
import { C as ControlEvidence, A as AgentAction, a as AppilotsLocale, b as AgentPermissions, c as AppilotsEvent, W as WebNavigationAdapter, S as ScreenActionMetadataLike, d as ActionExecutionResult } from './AppilotsWebRuntime-DZF26UyU.mjs';
|
|
2
|
+
export { e as ActionDiagnose, f as ActionQueueMachine, g as AgentActionType, h as AppilotsClient, i as AppilotsEventHandler, j as AppilotsWebRuntime, k as AppilotsWebRuntimeOptions, l as ChatMessage, m as ChatSessionMachine, n as ChatSessionOptions, o as ChatSessionState, E as EscalationState, p as EscalationStrings, R as RateLimitedError, q as WebNavigationAdapterOptions, r as WebNavigationState, s as WebRoute, t as WebScreenMetadata, u as buildPath, v as matchRoute } from './AppilotsWebRuntime-DZF26UyU.mjs';
|
|
3
|
+
|
|
4
|
+
type ActionPresentationState = 'pending' | 'running' | 'success' | 'failed';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Snapshot types — the platform-agnostic "view model" of what the user
|
|
8
|
+
* is currently seeing on screen, sent to the AI agent so it has
|
|
9
|
+
* accurate visible state.
|
|
10
|
+
*
|
|
11
|
+
* Every platform walker (React Native fiber walk, web DOM walk, ...)
|
|
12
|
+
* produces this same shape; the wire contract it feeds is
|
|
13
|
+
* `agentSnapshotSchema` in `@appilots/shared`.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* How much the walker actually knows about an element's identifier.
|
|
17
|
+
*
|
|
18
|
+
* The observation used to say nothing here, so `btn-3` — an ordinal the
|
|
19
|
+
* walker invented — read to the model exactly like `testID="submit-order"`,
|
|
20
|
+
* which a developer wrote down on purpose. That is how a confident press on
|
|
21
|
+
* the wrong control happens.
|
|
22
|
+
*
|
|
23
|
+
* - `declared` the app named it: `testID` / `data-testid` /
|
|
24
|
+
* `accessibilityLabel` / `aria-label`. Stable across renders
|
|
25
|
+
* and across releases; safe to copy into a tool call.
|
|
26
|
+
* - `derived` folded from what the user can see — the button's own text,
|
|
27
|
+
* a `label` or `placeholder` prop. Stable as long as the copy
|
|
28
|
+
* does not change, and it changes with the app's language.
|
|
29
|
+
* - `positional` nothing but an ordinal in the current snapshot. Valid for
|
|
30
|
+
* this observation only: a re-render, a scroll or an inserted
|
|
31
|
+
* sibling moves it.
|
|
32
|
+
*
|
|
33
|
+
* ABSENT means unknown, NOT `declared` — clients published before this field
|
|
34
|
+
* existed send no provenance at all, and a missing value must never be read
|
|
35
|
+
* as the most trustworthy one.
|
|
36
|
+
*/
|
|
37
|
+
type IdentityProvenance = 'declared' | 'derived' | 'positional';
|
|
38
|
+
interface InputSnapshot {
|
|
39
|
+
/** Best identifier — testID/data-testid, accessibilityLabel/aria-label, or placeholder */
|
|
40
|
+
id?: string;
|
|
41
|
+
/** How `id` was obtained. See {@link IdentityProvenance}. */
|
|
42
|
+
provenance?: IdentityProvenance;
|
|
43
|
+
/**
|
|
44
|
+
* False when the control is mounted but currently outside the window —
|
|
45
|
+
* below the fold of a ScrollView, scrolled off the top, pushed sideways
|
|
46
|
+
* by a carousel.
|
|
47
|
+
*
|
|
48
|
+
* ABSENT MEANS UNKNOWN. The old React Native architecture cannot report a
|
|
49
|
+
* synchronous window-relative rect, and no SDK published before this
|
|
50
|
+
* field existed reports one at all; reading absence as `false` would make
|
|
51
|
+
* the agent refuse to press a control the user is looking at.
|
|
52
|
+
*/
|
|
53
|
+
onScreen?: boolean;
|
|
54
|
+
/** Human-readable label inferred from accessibility metadata or sibling text */
|
|
55
|
+
label?: string;
|
|
56
|
+
/** Current value (only present for controlled inputs) */
|
|
57
|
+
value?: string;
|
|
58
|
+
/** Placeholder text */
|
|
59
|
+
placeholder?: string;
|
|
60
|
+
/** Whether the input is editable */
|
|
61
|
+
editable?: boolean;
|
|
62
|
+
/** Whether the input is secure (password field) */
|
|
63
|
+
secure?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Tipo do campo.
|
|
66
|
+
*
|
|
67
|
+
* Os cinco primeiros vêm da metadata de input da plataforma. Os quatro
|
|
68
|
+
* últimos vêm do registry: um select, um date picker, um toggle ou um
|
|
69
|
+
* controle custom registrado por `useAppilotsField` não é `TextInput`,
|
|
70
|
+
* então o walker não o coleta — e sem eles a observação não dizia o que
|
|
71
|
+
* estava preenchido num formulário que os exige. O schema de wire já
|
|
72
|
+
* aceitava (`type` é string livre lá); só o tipo local era estrito.
|
|
73
|
+
*/
|
|
74
|
+
type?: 'text' | 'email' | 'number' | 'phone' | 'password' | 'select' | 'date' | 'toggle' | 'custom';
|
|
75
|
+
/**
|
|
76
|
+
* True when pressing return on this field submits — RN's
|
|
77
|
+
* `onSubmitEditing`, the web's implicit form submit.
|
|
78
|
+
*
|
|
79
|
+
* On a search box, a one-field login or a chat composer this IS the
|
|
80
|
+
* submit; the screen has no button and never will. Absent means the
|
|
81
|
+
* field declares no such handler, so the form needs a button.
|
|
82
|
+
*/
|
|
83
|
+
submitsOnReturn?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The app is asking for this field before the form can be submitted.
|
|
86
|
+
*
|
|
87
|
+
* ABSENT MEANS UNKNOWN, not optional: most apps never declare it, and
|
|
88
|
+
* reading absence as "not required" would let the agent submit a form
|
|
89
|
+
* it could have known was incomplete.
|
|
90
|
+
*/
|
|
91
|
+
required?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* The app is currently rejecting this field's value.
|
|
94
|
+
*
|
|
95
|
+
* This is the fact the agent used to recover by READING — the error
|
|
96
|
+
* copy next to the input ("Campo obrigatório", "Formato inválido").
|
|
97
|
+
* Carrying the fact as a boolean is what lets a redacted observation
|
|
98
|
+
* still support recovery, and it is cheaper than the sentence even
|
|
99
|
+
* when nothing is redacted.
|
|
100
|
+
*
|
|
101
|
+
* Absent means the app declares no validity state — never that the
|
|
102
|
+
* field is valid.
|
|
103
|
+
*/
|
|
104
|
+
invalid?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Whether the field currently holds anything.
|
|
107
|
+
*
|
|
108
|
+
* Deliberately its own field rather than an inference over `value`.
|
|
109
|
+
* The value belongs to the user and is the first thing a privacy
|
|
110
|
+
* policy withholds; the EXISTENCE of a value belongs to the agent and
|
|
111
|
+
* is what stops it from filling the same field twice on a later hop.
|
|
112
|
+
* Separating them is what lets the second survive without the first.
|
|
113
|
+
*/
|
|
114
|
+
filled?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* This input has keyboard focus right now.
|
|
117
|
+
*
|
|
118
|
+
* Tells apart "empty because nobody typed" from "empty because the
|
|
119
|
+
* user is typing in it at this moment" — the difference between
|
|
120
|
+
* completing a form and interrupting someone mid-sentence.
|
|
121
|
+
*/
|
|
122
|
+
focused?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* True when this input lives inside a currently-visible modal. When a
|
|
125
|
+
* modal is open, only inModal elements can actually receive input —
|
|
126
|
+
* everything else is behind the overlay.
|
|
127
|
+
*/
|
|
128
|
+
inModal?: boolean;
|
|
129
|
+
}
|
|
130
|
+
interface ButtonSnapshot {
|
|
131
|
+
controlEvidence?: ControlEvidence;
|
|
132
|
+
/** Best identifier — testID/data-testid, accessibilityLabel/aria-label, or inferred from child text */
|
|
133
|
+
id?: string;
|
|
134
|
+
/** How `id` was obtained. See {@link IdentityProvenance}. */
|
|
135
|
+
provenance?: IdentityProvenance;
|
|
136
|
+
/** False when the client can observe this button but cannot bind its id to an exact control. */
|
|
137
|
+
dispatchable?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* False when the control is mounted but currently outside the window —
|
|
140
|
+
* below the fold of a ScrollView, scrolled off the top, pushed sideways
|
|
141
|
+
* by a carousel.
|
|
142
|
+
*
|
|
143
|
+
* ABSENT MEANS UNKNOWN. The old React Native architecture cannot report a
|
|
144
|
+
* synchronous window-relative rect, and no SDK published before this
|
|
145
|
+
* field existed reports one at all; reading absence as `false` would make
|
|
146
|
+
* the agent refuse to press a control the user is looking at.
|
|
147
|
+
*/
|
|
148
|
+
onScreen?: boolean;
|
|
149
|
+
/** Human-readable label — usually the visible text inside the button */
|
|
150
|
+
label?: string;
|
|
151
|
+
/** Whether the button is disabled */
|
|
152
|
+
disabled?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Whether this control is currently in its ON state.
|
|
155
|
+
*
|
|
156
|
+
* Covers both accessibility states that mean it, because the agent
|
|
157
|
+
* needs the same thing from either: `accessibilityState.selected`
|
|
158
|
+
* (grouped, mutually-exclusive controls — segmented controls, radio
|
|
159
|
+
* groups, each option its own pressable target) and
|
|
160
|
+
* `accessibilityState.checked` (an independent checkbox).
|
|
161
|
+
*
|
|
162
|
+
* Absent means "not on OR not observable" — the walker cannot tell a
|
|
163
|
+
* custom checkbox that declares no a11y state from an ordinary button,
|
|
164
|
+
* so absence is never proof that a box is unticked.
|
|
165
|
+
*/
|
|
166
|
+
selected?: boolean;
|
|
167
|
+
/** True when this button lives inside a currently-visible modal. */
|
|
168
|
+
inModal?: boolean;
|
|
169
|
+
}
|
|
170
|
+
interface ToggleSnapshot {
|
|
171
|
+
/** Best identifier */
|
|
172
|
+
id?: string;
|
|
173
|
+
/** How `id` was obtained. See {@link IdentityProvenance}. */
|
|
174
|
+
provenance?: IdentityProvenance;
|
|
175
|
+
/**
|
|
176
|
+
* False when the control is mounted but currently outside the window —
|
|
177
|
+
* below the fold of a ScrollView, scrolled off the top, pushed sideways
|
|
178
|
+
* by a carousel.
|
|
179
|
+
*
|
|
180
|
+
* ABSENT MEANS UNKNOWN. The old React Native architecture cannot report a
|
|
181
|
+
* synchronous window-relative rect, and no SDK published before this
|
|
182
|
+
* field existed reports one at all; reading absence as `false` would make
|
|
183
|
+
* the agent refuse to press a control the user is looking at.
|
|
184
|
+
*/
|
|
185
|
+
onScreen?: boolean;
|
|
186
|
+
/** Human-readable label */
|
|
187
|
+
label?: string;
|
|
188
|
+
/** Current on/off state */
|
|
189
|
+
value?: boolean;
|
|
190
|
+
/** True when this toggle lives inside a currently-visible modal. */
|
|
191
|
+
inModal?: boolean;
|
|
192
|
+
}
|
|
193
|
+
interface SliderSnapshot {
|
|
194
|
+
/** Registry id — the executable handle. */
|
|
195
|
+
id?: string;
|
|
196
|
+
/** How `id` was obtained. See {@link IdentityProvenance}. */
|
|
197
|
+
provenance?: IdentityProvenance;
|
|
198
|
+
/**
|
|
199
|
+
* False when the control is mounted but currently outside the window —
|
|
200
|
+
* below the fold of a ScrollView, scrolled off the top, pushed sideways
|
|
201
|
+
* by a carousel.
|
|
202
|
+
*
|
|
203
|
+
* ABSENT MEANS UNKNOWN. The old React Native architecture cannot report a
|
|
204
|
+
* synchronous window-relative rect, and no SDK published before this
|
|
205
|
+
* field existed reports one at all; reading absence as `false` would make
|
|
206
|
+
* the agent refuse to press a control the user is looking at.
|
|
207
|
+
*/
|
|
208
|
+
onScreen?: boolean;
|
|
209
|
+
/** Human-readable label */
|
|
210
|
+
label?: string;
|
|
211
|
+
/** Current numeric value */
|
|
212
|
+
value?: number;
|
|
213
|
+
/** Lower bound the executor clamps to */
|
|
214
|
+
min?: number;
|
|
215
|
+
/** Upper bound the executor clamps to */
|
|
216
|
+
max?: number;
|
|
217
|
+
/** Step the executor snaps to (omitted = continuous) */
|
|
218
|
+
step?: number;
|
|
219
|
+
/** Whether the slider is currently disabled */
|
|
220
|
+
disabled?: boolean;
|
|
221
|
+
/** True when this slider lives inside a currently-visible modal. */
|
|
222
|
+
inModal?: boolean;
|
|
223
|
+
}
|
|
224
|
+
interface ListItemSnapshot {
|
|
225
|
+
/** Whether this row intersects the list viewport, when geometry is available. */
|
|
226
|
+
onScreen?: boolean;
|
|
227
|
+
/** 1-indexed position within the parent list (matches "selecione o terceiro"). */
|
|
228
|
+
index: number;
|
|
229
|
+
/**
|
|
230
|
+
* 0-based index of this row in the list's backing DATA, when known.
|
|
231
|
+
* For scrolled/virtualized lists this differs from `index`.
|
|
232
|
+
*/
|
|
233
|
+
dataIndex?: number;
|
|
234
|
+
/** Framework key of the row, if present (typically the item's domain id). */
|
|
235
|
+
reactKey?: string;
|
|
236
|
+
/** Runtime key supplied by list tracking, if available. */
|
|
237
|
+
itemKey?: string;
|
|
238
|
+
/** Texts captured from this item's subtree, preserving row association. */
|
|
239
|
+
texts: string[];
|
|
240
|
+
/** Buttons inside this item — e.g. an inline "Edit" button on a row. */
|
|
241
|
+
buttons: ButtonSnapshot[];
|
|
242
|
+
/** Inputs inside this item — rare but possible (inline edit row). */
|
|
243
|
+
inputs: InputSnapshot[];
|
|
244
|
+
/** Toggles inside this item. */
|
|
245
|
+
toggles: ToggleSnapshot[];
|
|
246
|
+
/**
|
|
247
|
+
* Synthetic id assigned by the walker. Stable within a single
|
|
248
|
+
* snapshot; format `list-<L>-item-<I>` (0-indexed L, 1-indexed I).
|
|
249
|
+
* Used by tap-by-ordinal resolution in the executor.
|
|
250
|
+
*/
|
|
251
|
+
syntheticId: string;
|
|
252
|
+
}
|
|
253
|
+
interface ListSnapshot {
|
|
254
|
+
/** Measured rows intersecting the list viewport; absent means unmeasurable. */
|
|
255
|
+
viewportItemCount?: number;
|
|
256
|
+
/** Mission-local exploration metadata; positions are 0-based, never action targets. */
|
|
257
|
+
exploration?: {
|
|
258
|
+
revision: number;
|
|
259
|
+
observedItemCount: number;
|
|
260
|
+
observedRanges: Array<{
|
|
261
|
+
start: number;
|
|
262
|
+
end: number;
|
|
263
|
+
}>;
|
|
264
|
+
rangesTruncated: boolean;
|
|
265
|
+
coverage: 'partial' | 'all-loaded';
|
|
266
|
+
pagination: 'possible' | 'not-declared';
|
|
267
|
+
scrollSteps: number;
|
|
268
|
+
remainingScrollSteps: number;
|
|
269
|
+
consecutiveNoProgress: number;
|
|
270
|
+
lastScroll?: 'moved' | 'no-progress' | 'boundary' | 'unverified';
|
|
271
|
+
};
|
|
272
|
+
/** 0-indexed list ordinal — multiple lists on one screen get 0, 1, 2... */
|
|
273
|
+
index: number;
|
|
274
|
+
/** Runtime list id when tracking or explicit props provide one. */
|
|
275
|
+
id?: string;
|
|
276
|
+
/** The container component/tag name as observed by the walker. */
|
|
277
|
+
containerType: string;
|
|
278
|
+
/**
|
|
279
|
+
* Source that identified this list. `'fiber'`/`'auto-tracked'` are
|
|
280
|
+
* the walker's own discovery tags (a DOM walker reports
|
|
281
|
+
* `'auto-tracked'` for app-annotated lists and omits the field for
|
|
282
|
+
* heuristically-detected ones); `'registry'` means the list came
|
|
283
|
+
* from the SDK's list registry rather than the tree walk.
|
|
284
|
+
*/
|
|
285
|
+
source?: 'fiber' | 'auto-tracked' | 'registry';
|
|
286
|
+
/**
|
|
287
|
+
* How many items the list renders FROM — its `data.length`, which for
|
|
288
|
+
* a paginated list is the page and not the collection.
|
|
289
|
+
*/
|
|
290
|
+
itemCount?: number;
|
|
291
|
+
/**
|
|
292
|
+
* Size of the whole collection when the app declared it.
|
|
293
|
+
*
|
|
294
|
+
* The three counts answer three different questions and a list that
|
|
295
|
+
* pages needs all three: `visibleItemCount` is what is mounted,
|
|
296
|
+
* `itemCount` is what is loaded, `totalItemCount` is what exists.
|
|
297
|
+
* Undefined means unknown — it is never a copy of `itemCount`.
|
|
298
|
+
*/
|
|
299
|
+
totalItemCount?: number;
|
|
300
|
+
/** Number of row items captured in this snapshot. */
|
|
301
|
+
visibleItemCount?: number;
|
|
302
|
+
/** True when the list reports a refresh/loading state. */
|
|
303
|
+
refreshing?: boolean;
|
|
304
|
+
/** True when total item count is known and zero. */
|
|
305
|
+
empty?: boolean;
|
|
306
|
+
/** Human-readable label if the app supplied one. */
|
|
307
|
+
label?: string;
|
|
308
|
+
/** Items in visible order. */
|
|
309
|
+
items: ListItemSnapshot[];
|
|
310
|
+
/**
|
|
311
|
+
* Lightweight text projection of the list's FULL data set (capped),
|
|
312
|
+
* so the agent can see/search rows that virtualization keeps
|
|
313
|
+
* unmounted. Each entry: 0-based data index, stable key, short text.
|
|
314
|
+
*/
|
|
315
|
+
dataPreview?: ListDataPreviewEntry[];
|
|
316
|
+
/** Current vertical scroll offset in px, when readable. */
|
|
317
|
+
scrollOffsetY?: number;
|
|
318
|
+
/** True when there is scrollable content above the viewport. */
|
|
319
|
+
canScrollUp?: boolean;
|
|
320
|
+
/** True when there is scrollable content below the viewport. */
|
|
321
|
+
canScrollDown?: boolean;
|
|
322
|
+
}
|
|
323
|
+
interface ListDataPreviewEntry {
|
|
324
|
+
/** 0-based index in the list's backing data. */
|
|
325
|
+
index: number;
|
|
326
|
+
/** Stable key from the item's domain id when available. */
|
|
327
|
+
key?: string;
|
|
328
|
+
/** Short human-readable projection of the item (capped length). */
|
|
329
|
+
text: string;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* A scrollable surface that is NOT a collection — a long form, a detail
|
|
333
|
+
* page, a settings screen inside a `ScrollView`.
|
|
334
|
+
*
|
|
335
|
+
* It exists as its own concept, and not as a `ListSnapshot` with zero
|
|
336
|
+
* rows, because everything the agent knows how to do with a list
|
|
337
|
+
* (ordinals, totals, "select the third one") is meaningless here. The
|
|
338
|
+
* only affordance is paging toward content below the fold — and without
|
|
339
|
+
* it, a screen taller than the viewport ends at the fold.
|
|
340
|
+
*/
|
|
341
|
+
interface ScrollableSnapshot {
|
|
342
|
+
/** Runtime id — the handle `scroll_list` addresses. */
|
|
343
|
+
id: string;
|
|
344
|
+
/** The container component as observed: ScrollView, ... */
|
|
345
|
+
containerType: string;
|
|
346
|
+
/** Human-readable label if the app supplied one. */
|
|
347
|
+
label?: string;
|
|
348
|
+
/** Current scroll offset in px. */
|
|
349
|
+
scrollOffsetY?: number;
|
|
350
|
+
/** True when there is content above the viewport. */
|
|
351
|
+
canScrollUp?: boolean;
|
|
352
|
+
/** True when there is content below the viewport. */
|
|
353
|
+
canScrollDown?: boolean;
|
|
354
|
+
/** True when the surface scrolls sideways rather than vertically. */
|
|
355
|
+
horizontal?: boolean;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* A platform dialog covering the screen — React Native's `Alert.alert`,
|
|
359
|
+
* an action sheet, an OS permission prompt.
|
|
360
|
+
*
|
|
361
|
+
* It renders outside React, so no amount of tree walking finds it. It
|
|
362
|
+
* has to be reported separately or the agent keeps operating the app
|
|
363
|
+
* underneath a dialog that blocks every real finger.
|
|
364
|
+
*/
|
|
365
|
+
interface NativeDialogSnapshot {
|
|
366
|
+
/** Stable for as long as this dialog is open. */
|
|
367
|
+
id: string;
|
|
368
|
+
title?: string;
|
|
369
|
+
message?: string;
|
|
370
|
+
/** The buttons the user can press. Never empty. */
|
|
371
|
+
buttons: Array<{
|
|
372
|
+
label: string;
|
|
373
|
+
style?: 'default' | 'cancel' | 'destructive';
|
|
374
|
+
}>;
|
|
375
|
+
}
|
|
376
|
+
interface ChoiceOptionSnapshot {
|
|
377
|
+
/** 1-indexed option position within this group. */
|
|
378
|
+
index: number;
|
|
379
|
+
/** Stable-enough id for the current snapshot/action turn. */
|
|
380
|
+
syntheticId: string;
|
|
381
|
+
/** Best target id if this option is backed by a pressable component. */
|
|
382
|
+
targetId?: string;
|
|
383
|
+
/** Human-readable option label. */
|
|
384
|
+
label?: string;
|
|
385
|
+
/** Text segments that belong to this option. */
|
|
386
|
+
texts: string[];
|
|
387
|
+
/** Whether this option appears selected. */
|
|
388
|
+
selected?: boolean;
|
|
389
|
+
/** Whether this option appears disabled. */
|
|
390
|
+
disabled?: boolean;
|
|
391
|
+
}
|
|
392
|
+
interface ChoiceGroupSnapshot {
|
|
393
|
+
/** 0-indexed group ordinal on the current screen. */
|
|
394
|
+
index: number;
|
|
395
|
+
/** Runtime id when known, usually inherited from a list/collection. */
|
|
396
|
+
id?: string;
|
|
397
|
+
/** Human-readable label when known. */
|
|
398
|
+
label?: string;
|
|
399
|
+
/** Source that produced this choice group. */
|
|
400
|
+
source?: 'list' | 'buttons' | 'heuristic';
|
|
401
|
+
/** Visible options in order. */
|
|
402
|
+
options: ChoiceOptionSnapshot[];
|
|
403
|
+
}
|
|
404
|
+
interface InteractionElementListContext {
|
|
405
|
+
listIndex?: number;
|
|
406
|
+
listId?: string;
|
|
407
|
+
listLabel?: string;
|
|
408
|
+
itemIndex?: number;
|
|
409
|
+
itemKey?: string;
|
|
410
|
+
reactKey?: string;
|
|
411
|
+
syntheticId?: string;
|
|
412
|
+
}
|
|
413
|
+
interface InteractionElementSnapshot {
|
|
414
|
+
/** False means observation-only; absence preserves legacy client behavior. */
|
|
415
|
+
dispatchable?: boolean;
|
|
416
|
+
/** Stable id for the current screen/content, preferred for tool calls. */
|
|
417
|
+
id: string;
|
|
418
|
+
/** Semantic UI role. */
|
|
419
|
+
role: 'option' | 'button' | 'input' | 'toggle' | 'slider' | 'listItem';
|
|
420
|
+
/** Human-readable label. */
|
|
421
|
+
label?: string;
|
|
422
|
+
/** Text segments associated with this element. */
|
|
423
|
+
texts: string[];
|
|
424
|
+
/** Actions supported by this element. */
|
|
425
|
+
actions: Array<'press' | 'focus' | 'toggle' | 'setValue'>;
|
|
426
|
+
/** Whether the element is currently disabled. */
|
|
427
|
+
disabled?: boolean;
|
|
428
|
+
/** Whether the element appears selected. */
|
|
429
|
+
selected?: boolean;
|
|
430
|
+
/** Source that produced the element. */
|
|
431
|
+
source?: 'list' | 'button' | 'input' | 'toggle' | 'slider' | 'choice';
|
|
432
|
+
/**
|
|
433
|
+
* How the underlying control's identifier was obtained. Carried up from
|
|
434
|
+
* the snapshot entry this element was derived from, so a consumer that
|
|
435
|
+
* only reads `elements` still knows what it is trusting. See
|
|
436
|
+
* {@link IdentityProvenance}.
|
|
437
|
+
*/
|
|
438
|
+
provenance?: IdentityProvenance;
|
|
439
|
+
/**
|
|
440
|
+
* False when the control is mounted but currently outside the window —
|
|
441
|
+
* below the fold of a ScrollView, scrolled off the top, pushed sideways
|
|
442
|
+
* by a carousel.
|
|
443
|
+
*
|
|
444
|
+
* ABSENT MEANS UNKNOWN. The old React Native architecture cannot report a
|
|
445
|
+
* synchronous window-relative rect, and no SDK published before this
|
|
446
|
+
* field existed reports one at all; reading absence as `false` would make
|
|
447
|
+
* the agent refuse to press a control the user is looking at.
|
|
448
|
+
*/
|
|
449
|
+
onScreen?: boolean;
|
|
450
|
+
/** Legacy/fallback target id, if any. */
|
|
451
|
+
targetId?: string;
|
|
452
|
+
/** Context for row/list options. */
|
|
453
|
+
listContext?: InteractionElementListContext;
|
|
454
|
+
/**
|
|
455
|
+
* True when the underlying component lives inside a currently-visible
|
|
456
|
+
* modal — the only targets actually touchable while the overlay is up.
|
|
457
|
+
*/
|
|
458
|
+
inModal?: boolean;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* What changed between the previous observation and this one.
|
|
462
|
+
*
|
|
463
|
+
* The client holds both snapshots; the server only ever sees one. So the
|
|
464
|
+
* question the agent loop asks most often — "did the action I just took
|
|
465
|
+
* do anything?" — is one the client can answer as a FACT and the server
|
|
466
|
+
* can only guess at. Today it guesses: `effect: 'none'` on the turn trail
|
|
467
|
+
* is derived server-side from heuristics over a single snapshot.
|
|
468
|
+
*
|
|
469
|
+
* Everything here is shape, never content: counts, booleans, and field
|
|
470
|
+
* ids that the app declared itself. That is not an accident of design —
|
|
471
|
+
* it is what lets this survive a redacted or content-free observation
|
|
472
|
+
* intact, and it is why the most useful signal in the observation is also
|
|
473
|
+
* the cheapest one to send.
|
|
474
|
+
*
|
|
475
|
+
* ABSENT vs `unchanged: true` is the load-bearing distinction, and it is
|
|
476
|
+
* the same one `truncated` exists to make. Absent means there was no
|
|
477
|
+
* previous observation to compare against (the first capture of a
|
|
478
|
+
* mission). `unchanged: true` means we DID compare and nothing moved —
|
|
479
|
+
* which is the strongest evidence there is that an action did nothing.
|
|
480
|
+
*/
|
|
481
|
+
interface SnapshotDelta {
|
|
482
|
+
/** The active route is not the one the previous observation reported. */
|
|
483
|
+
routeChanged?: boolean;
|
|
484
|
+
/** A modal or native dialog is up now and was not before. */
|
|
485
|
+
modalOpened?: boolean;
|
|
486
|
+
/** A modal or native dialog was up before and is gone now. */
|
|
487
|
+
modalClosed?: boolean;
|
|
488
|
+
/** A loading indicator appeared. */
|
|
489
|
+
loadingStarted?: boolean;
|
|
490
|
+
/** A loading indicator that was showing is gone. */
|
|
491
|
+
loadingFinished?: boolean;
|
|
492
|
+
/** How many distinct visible texts are present now that were not before. */
|
|
493
|
+
textsAdded?: number;
|
|
494
|
+
/** How many distinct visible texts are gone. */
|
|
495
|
+
textsRemoved?: number;
|
|
496
|
+
/** Zero-based indexes of newly visible buttons in this snapshot, capped at 12.
|
|
497
|
+
* No derived ids or copy travel in the delta; render only from current buttons.
|
|
498
|
+
*/
|
|
499
|
+
buttonsAddedIndices?: number[];
|
|
500
|
+
/** Number of previously visible button identities no longer visible. */
|
|
501
|
+
buttonsRemoved?: number;
|
|
502
|
+
/** Net change in mounted list rows, summed across every list. */
|
|
503
|
+
visibleRowsDelta?: number;
|
|
504
|
+
/**
|
|
505
|
+
* Net change in the lists' reported DATA totals, summed. This is the
|
|
506
|
+
* one that answers "did the record actually get created", because it
|
|
507
|
+
* moves even when virtualization keeps the new row unmounted.
|
|
508
|
+
*/
|
|
509
|
+
totalRowsDelta?: number;
|
|
510
|
+
/**
|
|
511
|
+
* Fields that went from empty to filled. Declared ids only — a
|
|
512
|
+
* `derived` id is folded from visible copy, so publishing it here
|
|
513
|
+
* would smuggle content through a field that claims to carry none.
|
|
514
|
+
*/
|
|
515
|
+
fieldsNewlyFilled?: string[];
|
|
516
|
+
/** Fields that went from filled to empty. Declared ids only. */
|
|
517
|
+
fieldsCleared?: string[];
|
|
518
|
+
/** Some field is reporting invalid that was not reporting it before. */
|
|
519
|
+
invalidAppeared?: boolean;
|
|
520
|
+
/**
|
|
521
|
+
* Nothing above fired: we compared two observations and the screen is
|
|
522
|
+
* structurally identical. Present only when every other field is
|
|
523
|
+
* absent, so a reader never has to check all of them to know.
|
|
524
|
+
*/
|
|
525
|
+
unchanged?: boolean;
|
|
526
|
+
}
|
|
527
|
+
interface ScreenSnapshot {
|
|
528
|
+
/** The currently active route name, if known */
|
|
529
|
+
route: string | null;
|
|
530
|
+
/** All visible static text */
|
|
531
|
+
texts: string[];
|
|
532
|
+
/** All text inputs currently rendered (and visible) */
|
|
533
|
+
inputs: InputSnapshot[];
|
|
534
|
+
/** All button-like components */
|
|
535
|
+
buttons: ButtonSnapshot[];
|
|
536
|
+
/** All toggle components */
|
|
537
|
+
toggles: ToggleSnapshot[];
|
|
538
|
+
/** Sliders / adjustable numeric controls. */
|
|
539
|
+
sliders: SliderSnapshot[];
|
|
540
|
+
/** Whether a loading indicator is visible */
|
|
541
|
+
loading: boolean;
|
|
542
|
+
/** Whether a modal is currently open */
|
|
543
|
+
modalOpen: boolean;
|
|
544
|
+
/**
|
|
545
|
+
* A native dialog covering the screen, when the SDK could observe one.
|
|
546
|
+
*
|
|
547
|
+
* Its presence also forces `modalOpen`, because for every purpose the
|
|
548
|
+
* agent cares about it IS a modal — nothing behind it is touchable.
|
|
549
|
+
* Absence is not proof there is no dialog: an OS permission prompt or
|
|
550
|
+
* a share sheet cannot be instrumented at all.
|
|
551
|
+
*/
|
|
552
|
+
nativeDialog?: NativeDialogSnapshot;
|
|
553
|
+
/**
|
|
554
|
+
* Lists detected in the visible tree. Each list's items have their
|
|
555
|
+
* own per-item texts/buttons/inputs/toggles, NOT duplicated in the
|
|
556
|
+
* flat top-level arrays — preserving the row association the flat
|
|
557
|
+
* shape destroys.
|
|
558
|
+
*/
|
|
559
|
+
lists: ListSnapshot[];
|
|
560
|
+
/**
|
|
561
|
+
* Choice groups detected from visible cards/rows/chips/buttons, used
|
|
562
|
+
* for select-like flows where no text input exists.
|
|
563
|
+
*/
|
|
564
|
+
choiceGroups: ChoiceGroupSnapshot[];
|
|
565
|
+
/**
|
|
566
|
+
* Scrollable surfaces that carry no rows. Absent/empty means either
|
|
567
|
+
* the screen does not scroll or the SDK could not observe that it
|
|
568
|
+
* does — never that the visible content is all the content.
|
|
569
|
+
*/
|
|
570
|
+
scrollables?: ScrollableSnapshot[];
|
|
571
|
+
/**
|
|
572
|
+
* Interaction graph: visible actionable elements with stable ids,
|
|
573
|
+
* semantic roles, labels, and execution fallbacks. Agents should
|
|
574
|
+
* prefer these ids over synthetic ordinal handles.
|
|
575
|
+
*/
|
|
576
|
+
elements: InteractionElementSnapshot[];
|
|
577
|
+
/**
|
|
578
|
+
* Set when the walker's output exceeded the wire contract and
|
|
579
|
+
* `clampSnapshotToWireLimits` dropped part of it (see
|
|
580
|
+
* `introspection/wireLimits.ts`). Absent means the observation is
|
|
581
|
+
* complete.
|
|
582
|
+
*
|
|
583
|
+
* The server surfaces this to the model: a screen whose text was cut
|
|
584
|
+
* at 500 entries must not be read as a screen with only 500 things on
|
|
585
|
+
* it. Without the flag a truncated observation is indistinguishable
|
|
586
|
+
* from a short one.
|
|
587
|
+
*/
|
|
588
|
+
truncated?: boolean;
|
|
589
|
+
/**
|
|
590
|
+
* What moved since the previous observation. See {@link SnapshotDelta}
|
|
591
|
+
* — absent means there was nothing to compare against, which is a
|
|
592
|
+
* different statement from "nothing changed".
|
|
593
|
+
*
|
|
594
|
+
* Attached by the platform adapter rather than by the walker: the
|
|
595
|
+
* baseline has to be the last snapshot that was actually SENT, and
|
|
596
|
+
* `captureSnapshot` is also called for internal probes that never
|
|
597
|
+
* leave the device.
|
|
598
|
+
*/
|
|
599
|
+
delta?: SnapshotDelta;
|
|
600
|
+
/** Diagnostic counts for debugging */
|
|
601
|
+
stats?: {
|
|
602
|
+
visitedFibers: number;
|
|
603
|
+
skippedHidden: number;
|
|
604
|
+
/**
|
|
605
|
+
* How many controls the walker could name, and how well.
|
|
606
|
+
*
|
|
607
|
+
* `WalkDetectorCounts` counts RECOGNITIONS, not emissions, so a screen
|
|
608
|
+
* whose controls were all silently dropped still reported healthy
|
|
609
|
+
* detector numbers. This is the emission side: `positional` climbing is
|
|
610
|
+
* the signal that an app needs annotating, and comparing it between a
|
|
611
|
+
* debug and a release build is the first real measurement of what
|
|
612
|
+
* minification costs the agent.
|
|
613
|
+
*/
|
|
614
|
+
identity?: {
|
|
615
|
+
declared: number;
|
|
616
|
+
derived: number;
|
|
617
|
+
positional: number;
|
|
618
|
+
};
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/** Customer action labels. Raw payloads remain in the action/debug records. */
|
|
623
|
+
|
|
624
|
+
type BreadcrumbState = ActionPresentationState;
|
|
625
|
+
interface BreadcrumbItem {
|
|
626
|
+
label: string;
|
|
627
|
+
state: BreadcrumbState;
|
|
628
|
+
}
|
|
629
|
+
declare function describeAction(action: AgentAction, locale?: AppilotsLocale): BreadcrumbItem;
|
|
630
|
+
/**
|
|
631
|
+
* Convert the executor's raw error string into a short, user-facing
|
|
632
|
+
* reason that fits inside parentheses on the breadcrumb line. Returns
|
|
633
|
+
* `undefined` when there's no useful information to show — caller can
|
|
634
|
+
* then drop the parenthetical entirely.
|
|
635
|
+
*
|
|
636
|
+
* Heuristics:
|
|
637
|
+
* - Apply known-pattern rewrites (rejected, not found, network, etc.)
|
|
638
|
+
* - If the result looks technical (stack frame, HTTP status, JSON
|
|
639
|
+
* dump) or is suspiciously long, fall back to "algo deu errado".
|
|
640
|
+
* - Trim and lowercase the first letter so it reads naturally inside
|
|
641
|
+
* the parens after the action verb.
|
|
642
|
+
*/
|
|
643
|
+
declare function humanizeError(raw: string | undefined, _action?: AgentAction): string | undefined;
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* walkDom — the DOM/ARIA equivalent of the RN SDK's Fiber walker.
|
|
647
|
+
*
|
|
648
|
+
* Same output shape (`ScreenSnapshot`), same semantic rules (an element
|
|
649
|
+
* is exactly one of text/input/slider/button/toggle; list containers are
|
|
650
|
+
* not descended in the main pass; the same dedup keys), different
|
|
651
|
+
* mechanics: this reads the document and its accessibility metadata
|
|
652
|
+
* instead of a framework's internal tree. That is deliberate — it means
|
|
653
|
+
* the walker works identically against React, Vue, Svelte, or plain
|
|
654
|
+
* HTML, and it cannot break when a framework changes its internals.
|
|
655
|
+
*/
|
|
656
|
+
|
|
657
|
+
interface WalkDomOptions {
|
|
658
|
+
/** Subtree to observe. Defaults to `document.body`. */
|
|
659
|
+
root?: Element;
|
|
660
|
+
/** Route name for the snapshot, when the caller knows it. */
|
|
661
|
+
route?: string | null;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Walk the DOM and produce a `ScreenSnapshot`. `elements` are NOT
|
|
665
|
+
* derived here — `captureSnapshot` adds them, mirroring how the RN SDK
|
|
666
|
+
* splits walking from interaction-graph derivation.
|
|
667
|
+
*/
|
|
668
|
+
declare function walkDom(options?: WalkDomOptions): ScreenSnapshot;
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* captureSnapshot — walk the DOM, then derive the interaction graph.
|
|
672
|
+
*
|
|
673
|
+
* Split the same way the RN SDK splits it: `walkDom` produces the raw
|
|
674
|
+
* observation, `deriveInteractionElements` turns it into stable `el:`
|
|
675
|
+
* ids. Because that derivation lives in `@appilots/client-core` and
|
|
676
|
+
* reads only the snapshot, identical observed content yields identical
|
|
677
|
+
* element ids on web and React Native.
|
|
678
|
+
*/
|
|
679
|
+
|
|
680
|
+
declare function getRegisteredElement(id: string): InteractionElementSnapshot | undefined;
|
|
681
|
+
declare function registeredElements(): InteractionElementSnapshot[];
|
|
682
|
+
declare function captureSnapshot(options?: WalkDomOptions): ScreenSnapshot;
|
|
683
|
+
/**
|
|
684
|
+
* Structural fingerprint of the current screen — ids and enabled/
|
|
685
|
+
* checked state only, never text or values. Two probes with the same
|
|
686
|
+
* fingerprint mean nothing actionable changed, which is how the settle
|
|
687
|
+
* loop decides the UI has stopped moving.
|
|
688
|
+
*
|
|
689
|
+
* Mirrors `probeLoadingState`'s fingerprint in the RN SDK, including
|
|
690
|
+
* the sort (so a DOM reorder alone is not a change).
|
|
691
|
+
*/
|
|
692
|
+
interface LoadingProbeResult {
|
|
693
|
+
loading: boolean;
|
|
694
|
+
pressedDisabled: boolean;
|
|
695
|
+
pressedFound: boolean;
|
|
696
|
+
modalOpen: boolean;
|
|
697
|
+
fingerprint: string;
|
|
698
|
+
}
|
|
699
|
+
declare function probeLoadingState(pressedComponentId?: string | null, route?: string | null, options?: WalkDomOptions): LoadingProbeResult;
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Locator resolution — how a DOM element gets the id and label the
|
|
703
|
+
* agent addresses it by.
|
|
704
|
+
*
|
|
705
|
+
* Deliberately DOM + accessibility metadata only: no framework
|
|
706
|
+
* internals (no React Fiber, no Vue instance), so the same walker works
|
|
707
|
+
* against React, Vue, Svelte, or hand-written HTML.
|
|
708
|
+
*/
|
|
709
|
+
/** Attribute checked first — the app's explicit opt-in agent id. */
|
|
710
|
+
declare const APPILOTS_ID_ATTR = "data-appilots-id";
|
|
711
|
+
/** Marks a subtree the walker must not descend into. */
|
|
712
|
+
declare const APPILOTS_SKIP_ATTR = "data-appilots-skip";
|
|
713
|
+
/** Marks a list container and carries its stable id. */
|
|
714
|
+
declare const APPILOTS_LIST_ID_ATTR = "data-appilots-list-id";
|
|
715
|
+
/** Marks a row inside a list container. */
|
|
716
|
+
declare const APPILOTS_LIST_ITEM_ATTR = "data-appilots-list-item";
|
|
717
|
+
/** Optional stable key for a row (the item's domain id). */
|
|
718
|
+
declare const APPILOTS_ITEM_KEY_ATTR = "data-appilots-item-key";
|
|
719
|
+
/** Optional 0-based index of a row in the list's backing data. */
|
|
720
|
+
declare const APPILOTS_ITEM_INDEX_ATTR = "data-appilots-item-index";
|
|
721
|
+
/** Optional total data-set size when the DOM only holds a page of it. */
|
|
722
|
+
declare const APPILOTS_ITEM_COUNT_ATTR = "data-appilots-item-count";
|
|
723
|
+
/** Marks the agent's own chat UI so it never observes itself. */
|
|
724
|
+
declare const APPILOTS_CHAT_ATTR = "data-appilots-chat";
|
|
725
|
+
/** Marks a field whose value must never leave the device. */
|
|
726
|
+
declare const APPILOTS_SENSITIVE_ATTR = "data-appilots-sensitive";
|
|
727
|
+
/**
|
|
728
|
+
* Turn a human label into an id, mirroring the RN walker's
|
|
729
|
+
* `normalizeLabel`: strip diacritics, drop non-alphanumerics, and
|
|
730
|
+
* camelCase-join the words ("Salvar veículo" → "salvarVeiculo").
|
|
731
|
+
*/
|
|
732
|
+
declare function normalizeLabelToId(label: string): string;
|
|
733
|
+
/**
|
|
734
|
+
* The element's agent-facing id, in precedence order:
|
|
735
|
+
* `data-appilots-id` → `data-testid` → `id` → `name` → `aria-label`.
|
|
736
|
+
*
|
|
737
|
+
* `data-testid` sits high because it is the convention apps already use
|
|
738
|
+
* for e2e tests, so most apps get useful ids with zero extra markup.
|
|
739
|
+
*/
|
|
740
|
+
declare function bestId(el: Element): string | undefined;
|
|
741
|
+
/**
|
|
742
|
+
* The element's accessible name, following the parts of the ARIA
|
|
743
|
+
* name computation that matter here: `aria-label`, `aria-labelledby`,
|
|
744
|
+
* an associated `<label>`, then `title`/`placeholder`/`alt`.
|
|
745
|
+
*/
|
|
746
|
+
declare function accessibleName(el: Element): string | undefined;
|
|
747
|
+
/** The ARIA role: explicit `role` attribute, else the implicit one. */
|
|
748
|
+
declare function elementRole(el: Element): string | undefined;
|
|
749
|
+
/**
|
|
750
|
+
* Visible text directly owned by an element, used as a button's label.
|
|
751
|
+
* Mirrors the RN walker's `findChildText`: up to three text fragments
|
|
752
|
+
* containing at least one letter or digit, joined with ' · '.
|
|
753
|
+
*/
|
|
754
|
+
declare function readOwnText(el: Element, maxFragments?: number): string | undefined;
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Visibility — deciding whether the user can actually see and reach an
|
|
758
|
+
* element.
|
|
759
|
+
*
|
|
760
|
+
* Uses `Element.checkVisibility()` when the browser has it (it accounts
|
|
761
|
+
* for `content-visibility`, `display`, `visibility` and opacity in one
|
|
762
|
+
* call), and falls back to an explicit ancestor walk everywhere else.
|
|
763
|
+
* The fallback is what runs under jsdom/happy-dom in tests, where
|
|
764
|
+
* layout is not computed at all.
|
|
765
|
+
*/
|
|
766
|
+
/**
|
|
767
|
+
* True when this element hides itself and its subtree. Mirrors the RN
|
|
768
|
+
* walker's `shouldSkipSubtree` rules: an explicit opt-out marker, our
|
|
769
|
+
* own chat UI, `display: none`, and `opacity: 0` combined with
|
|
770
|
+
* `pointer-events: none` (both required — a fade-in animation mid-frame
|
|
771
|
+
* is still meant to be seen).
|
|
772
|
+
*/
|
|
773
|
+
declare function hidesSubtree(el: Element): boolean;
|
|
774
|
+
/**
|
|
775
|
+
* True when the element is visible to the user, considering ancestors.
|
|
776
|
+
* Prefers the browser's own `checkVisibility()`; the manual walk is the
|
|
777
|
+
* fallback for test DOMs and older browsers.
|
|
778
|
+
*/
|
|
779
|
+
declare function isVisible(el: Element): boolean;
|
|
780
|
+
interface ScrollMetrics {
|
|
781
|
+
offset: number;
|
|
782
|
+
visibleLength: number;
|
|
783
|
+
contentLength: number;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Read a scroll container's metrics. Returns undefined when the element
|
|
787
|
+
* reports no scrollable content — including test DOMs, where every
|
|
788
|
+
* layout number is zero and inventing scroll facts would be a lie.
|
|
789
|
+
*/
|
|
790
|
+
declare function readScrollMetrics(el: Element): ScrollMetrics | undefined;
|
|
791
|
+
/**
|
|
792
|
+
* Nearest scrollable ancestor (or the element itself), used to answer
|
|
793
|
+
* "can this list scroll further up/down".
|
|
794
|
+
*/
|
|
795
|
+
declare function findScrollContainer(el: Element): Element | undefined;
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Settling — waiting for the UI to stop moving before observing it.
|
|
799
|
+
*
|
|
800
|
+
* Same contract as the RN SDK's `waitForScreenSettle` /
|
|
801
|
+
* `waitForLoadingSettle`, with DOM signals instead of Fiber ones: the
|
|
802
|
+
* URL for route transitions, and `aria-busy`/disabled-submit/structural
|
|
803
|
+
* fingerprint for async work.
|
|
804
|
+
*/
|
|
805
|
+
interface ScreenSettleOptions {
|
|
806
|
+
expectingChange?: boolean;
|
|
807
|
+
fromScreen?: string | null;
|
|
808
|
+
fromSignature?: string | null;
|
|
809
|
+
targetScreen?: string | null;
|
|
810
|
+
maxMs?: number;
|
|
811
|
+
pollMs?: number;
|
|
812
|
+
stableReads?: number;
|
|
813
|
+
mountFlushMs?: number;
|
|
814
|
+
}
|
|
815
|
+
interface ScreenSettleResult {
|
|
816
|
+
screen: string | null;
|
|
817
|
+
transitioned: boolean;
|
|
818
|
+
timedOut: boolean;
|
|
819
|
+
waitedMs: number;
|
|
820
|
+
}
|
|
821
|
+
interface LoadingSettleOptions {
|
|
822
|
+
pressedComponentId?: string | null;
|
|
823
|
+
fromScreen?: string | null;
|
|
824
|
+
maxMs?: number;
|
|
825
|
+
pollMs?: number;
|
|
826
|
+
backoffFactor?: number;
|
|
827
|
+
pollMaxMs?: number;
|
|
828
|
+
stableReads?: number;
|
|
829
|
+
}
|
|
830
|
+
interface LoadingSettleResult {
|
|
831
|
+
settled: boolean;
|
|
832
|
+
transitioned: boolean;
|
|
833
|
+
loadingPending: boolean;
|
|
834
|
+
screen: string | null;
|
|
835
|
+
waitedMs: number;
|
|
836
|
+
probeCount: number;
|
|
837
|
+
}
|
|
838
|
+
interface SettleProbes {
|
|
839
|
+
getCurrentScreen(): string | null;
|
|
840
|
+
getCurrentScreenSignature(): string | null;
|
|
841
|
+
}
|
|
842
|
+
declare const routesBelongToSameFeature: (a: string, b: string) => boolean;
|
|
843
|
+
declare function screenDepartedBaseline(current: string | null, currentSignature: string | null, fromScreen: string | null, fromSignature: string | null): boolean;
|
|
844
|
+
/**
|
|
845
|
+
* Wait for a route transition to land, then for the route to hold
|
|
846
|
+
* still for a few reads, then flush a frame so the new screen's effects
|
|
847
|
+
* have run before we observe it.
|
|
848
|
+
*/
|
|
849
|
+
declare function waitForScreenSettle(probes: SettleProbes, options?: ScreenSettleOptions): Promise<ScreenSettleResult>;
|
|
850
|
+
/**
|
|
851
|
+
* Wait for async work kicked off by an interaction to finish. Fast path
|
|
852
|
+
* returns after ~one probe when nothing is busy, which is the common
|
|
853
|
+
* case; otherwise it polls with exponential backoff until the screen
|
|
854
|
+
* is quiescent (no loading indicator, the pressed control re-enabled,
|
|
855
|
+
* and a stable structural fingerprint).
|
|
856
|
+
*/
|
|
857
|
+
declare function waitForLoadingSettle(probes: SettleProbes, options?: LoadingSettleOptions): Promise<LoadingSettleResult>;
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Target resolution — turning an id the model emitted into a real DOM
|
|
861
|
+
* element.
|
|
862
|
+
*
|
|
863
|
+
* The model addresses controls by whatever id the snapshot showed it:
|
|
864
|
+
* a `data-testid`, an `el:` interaction-graph id, or a synthetic list
|
|
865
|
+
* ordinal (`list-0-item-3`). All three resolve here, with the same
|
|
866
|
+
* lenient-then-fuzzy ladder the RN executor uses, so a near-miss id
|
|
867
|
+
* still lands on the right control instead of failing the turn.
|
|
868
|
+
*/
|
|
869
|
+
interface ResolveOptions {
|
|
870
|
+
root?: Element | Document;
|
|
871
|
+
/** Restrict to controls that can be filled (inputs/selects/textareas). */
|
|
872
|
+
kind?: 'field' | 'target' | 'toggle' | 'any';
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Strip the kind prefixes apps conventionally add, so `btn-submit`
|
|
876
|
+
* matches a control registered as `submit` (and vice versa). Mirrors
|
|
877
|
+
* the RN executor's `stripComponentPrefix`.
|
|
878
|
+
*/
|
|
879
|
+
declare function stripComponentPrefix(componentId: string): string | null;
|
|
880
|
+
/** Rows of a list, in the order the walker saw them. */
|
|
881
|
+
declare function findListItemElements(listIndex: number, options?: ResolveOptions): {
|
|
882
|
+
container: Element;
|
|
883
|
+
items: Element[];
|
|
884
|
+
} | undefined;
|
|
885
|
+
/** `list-0-item-3` → `{ listIndex: 0, itemIndex: 3 }` (1-based item). */
|
|
886
|
+
declare function parseSyntheticListItemId(id: string): {
|
|
887
|
+
listIndex: number;
|
|
888
|
+
itemIndex: number;
|
|
889
|
+
} | null;
|
|
890
|
+
/** The row a synthetic ordinal points at. */
|
|
891
|
+
declare function resolveListItem(syntheticId: string, options?: ResolveOptions): Element | undefined;
|
|
892
|
+
/**
|
|
893
|
+
* The element a row's press should dispatch on.
|
|
894
|
+
*
|
|
895
|
+
* A row usually holds a primary control plus secondary ones — an "open"
|
|
896
|
+
* link next to a "delete" button. Two rules matter here:
|
|
897
|
+
*
|
|
898
|
+
* - Never pick a destructive control. "Open the second vehicle" must
|
|
899
|
+
* not delete it because delete happened to be the first button in
|
|
900
|
+
* the DOM.
|
|
901
|
+
* - Never fall back to the row itself when it holds controls. Clicking
|
|
902
|
+
* a bare `<li>` does nothing, and the action would report success
|
|
903
|
+
* while the user saw no change.
|
|
904
|
+
*
|
|
905
|
+
* Returns undefined when the row exposes only destructive controls, so
|
|
906
|
+
* the caller can fail with an ambiguous-target diagnose instead of
|
|
907
|
+
* guessing.
|
|
908
|
+
*/
|
|
909
|
+
declare function primaryControlOf(row: Element): Element | undefined;
|
|
910
|
+
interface ResolvedTarget {
|
|
911
|
+
element: Element;
|
|
912
|
+
/** How we found it — useful in diagnostics when a match was fuzzy. */
|
|
913
|
+
via: 'element-registry' | 'list-ordinal' | 'exact-id' | 'prefix-id' | 'fuzzy-label';
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Resolve an id to an element, trying (in order): the `el:` interaction
|
|
917
|
+
* registry, synthetic list ordinals, exact id attributes, prefix-
|
|
918
|
+
* stripped ids, then fuzzy label matching.
|
|
919
|
+
*/
|
|
920
|
+
declare function resolveTargetElement(rawId: string, options?: ResolveOptions): ResolvedTarget | undefined;
|
|
921
|
+
/** Ids the model could have meant — attached to a not-found diagnose. */
|
|
922
|
+
declare function candidateIds(options?: ResolveOptions, limit?: number): string[];
|
|
923
|
+
/** True when a modal is up and the target is behind it. */
|
|
924
|
+
declare function isOccludedByModal(el: Element, options?: ResolveOptions): boolean;
|
|
925
|
+
/** Visible, enabled controls inside the open modal — recovery hints. */
|
|
926
|
+
declare function modalCandidateLabels(options?: ResolveOptions, limit?: number): string[];
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* ActionExecutor — executes the six agent actions against the DOM.
|
|
930
|
+
*
|
|
931
|
+
* Mirrors the RN executor's contract exactly: the same permission gate,
|
|
932
|
+
* the same validation errors, the same `ActionDiagnose` categories, and
|
|
933
|
+
* the same lifecycle events. What differs is the mechanics underneath
|
|
934
|
+
* (DOM events instead of registry handles) and navigation, which goes
|
|
935
|
+
* through the injected `WebNavigationAdapter` rather than React
|
|
936
|
+
* Navigation.
|
|
937
|
+
*/
|
|
938
|
+
|
|
939
|
+
interface WebExecutorContext {
|
|
940
|
+
signal?: AbortSignal;
|
|
941
|
+
/**
|
|
942
|
+
* PARTIAL: every flag left out takes its default. See
|
|
943
|
+
* `resolveAgentPermissions` in @appilots/client-core — a config that
|
|
944
|
+
* named some of the flags used to deny the rest in silence.
|
|
945
|
+
*/
|
|
946
|
+
permissions?: Partial<AgentPermissions>;
|
|
947
|
+
emit: (event: AppilotsEvent) => void;
|
|
948
|
+
navigation: WebNavigationAdapter;
|
|
949
|
+
/** Subtree to act within. Defaults to the whole document. */
|
|
950
|
+
root?: Element | Document;
|
|
951
|
+
/**
|
|
952
|
+
* Actions the app declared for the current screen. Used to resolve
|
|
953
|
+
* the submit control by declaration rather than by guessing at copy.
|
|
954
|
+
*/
|
|
955
|
+
screenActions?: Array<ScreenActionMetadataLike | string>;
|
|
956
|
+
/**
|
|
957
|
+
* True when the user already approved a destructive confirm for this
|
|
958
|
+
* action in chat — the app's own `window.confirm` is auto-accepted
|
|
959
|
+
* once so the user is not asked the same question twice.
|
|
960
|
+
*/
|
|
961
|
+
confirmedDestructive?: boolean;
|
|
962
|
+
}
|
|
963
|
+
declare function executeAction(action: AgentAction, context: WebExecutorContext): Promise<ActionExecutionResult>;
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* DOM event dispatch — the primitives every action handler builds on.
|
|
967
|
+
*
|
|
968
|
+
* Writing to a controlled React input is the subtle one: assigning
|
|
969
|
+
* `element.value` directly does not notify React, because React
|
|
970
|
+
* installs its own value setter on the element instance and tracks the
|
|
971
|
+
* last value it wrote. We call the *prototype's* native setter (which
|
|
972
|
+
* updates React's tracker) and then dispatch a bubbling `input` event,
|
|
973
|
+
* which is what React's synthetic `onChange` actually listens for. The
|
|
974
|
+
* same sequence works for Vue's `v-model` and for plain listeners.
|
|
975
|
+
*/
|
|
976
|
+
/** Focus an element, tolerating hosts where focus() is unavailable. */
|
|
977
|
+
declare function focusElement(el: Element): void;
|
|
978
|
+
/**
|
|
979
|
+
* Set a form control's value so the owning framework observes it.
|
|
980
|
+
* Returns false for a non-value control or an unavailable select option.
|
|
981
|
+
*/
|
|
982
|
+
declare function setControlValue(el: Element, value: string): boolean;
|
|
983
|
+
/** Read a control's current value, whatever kind it is. */
|
|
984
|
+
declare function readControlValue(el: Element): string;
|
|
985
|
+
/** Flip a checkbox/switch and notify the framework. */
|
|
986
|
+
declare function setToggleValue(el: Element, value: boolean): boolean;
|
|
987
|
+
declare function readToggleValue(el: Element): boolean;
|
|
988
|
+
/**
|
|
989
|
+
* Click an element the way a user would: pointer/mouse sequence first
|
|
990
|
+
* (so handlers bound to mousedown/pointerup fire), then `click()` so
|
|
991
|
+
* default behavior (form submission, link navigation) still happens.
|
|
992
|
+
*/
|
|
993
|
+
declare function clickElement(el: Element): void;
|
|
994
|
+
/** Long-press: a click preceded by a held pointer, for context menus. */
|
|
995
|
+
declare function longPressElement(el: Element): void;
|
|
996
|
+
/** Scroll an element into view, tolerating hosts without the API. */
|
|
997
|
+
declare function scrollIntoView(el: Element): void;
|
|
998
|
+
/** Scroll a container to an absolute offset. */
|
|
999
|
+
declare function scrollToOffset(container: Element, offset: number): boolean;
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* GENERATED by scripts/release/sync-sdk-versions.mjs — do not edit.
|
|
1003
|
+
*
|
|
1004
|
+
* The version `@appilots/web-sdk` reports on the wire
|
|
1005
|
+
* (`X-Appilots-Sdk-Version`). Kept identical to package.json by the
|
|
1006
|
+
* release flow; `version.test.ts` fails if the two ever disagree.
|
|
1007
|
+
*/
|
|
1008
|
+
declare const SDK_VERSION = "0.2.0";
|
|
1009
|
+
|
|
1010
|
+
export { APPILOTS_CHAT_ATTR, APPILOTS_ID_ATTR, APPILOTS_ITEM_COUNT_ATTR, APPILOTS_ITEM_INDEX_ATTR, APPILOTS_ITEM_KEY_ATTR, APPILOTS_LIST_ID_ATTR, APPILOTS_LIST_ITEM_ATTR, APPILOTS_SENSITIVE_ATTR, APPILOTS_SKIP_ATTR, ActionExecutionResult, AgentAction, AgentPermissions, AppilotsEvent, type LoadingProbeResult, type LoadingSettleOptions, type LoadingSettleResult, type ResolveOptions, type ResolvedTarget, SDK_VERSION, type ScreenSettleOptions, type ScreenSettleResult, type ScreenSnapshot, type ScrollMetrics, type SettleProbes, type WalkDomOptions, type WebExecutorContext, WebNavigationAdapter, accessibleName, bestId, candidateIds, captureSnapshot, clickElement, describeAction, elementRole, executeAction, findListItemElements, findScrollContainer, focusElement, getRegisteredElement, hidesSubtree, humanizeError, isOccludedByModal, isVisible, longPressElement, modalCandidateLabels, normalizeLabelToId, parseSyntheticListItemId, primaryControlOf, probeLoadingState, readControlValue, readOwnText, readScrollMetrics, readToggleValue, registeredElements, resolveListItem, resolveTargetElement, routesBelongToSameFeature, screenDepartedBaseline, scrollIntoView, scrollToOffset, setControlValue, setToggleValue, stripComponentPrefix, waitForLoadingSettle, waitForScreenSettle, walkDom };
|