@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.
@@ -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 };