@appilots/sdk 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1543 @@
1
+ import * as React$1 from 'react';
2
+ import React__default from 'react';
3
+
4
+ /**
5
+ * Theme tokens — the source of truth for any color, font, radius or
6
+ * shadow used inside the SDK's chat UI. Components must read from these
7
+ * tokens (via {@link useAppilotsTheme}) rather than hardcoding values, so
8
+ * a developer who sets a `theme` prop or dashboard config can re-skin
9
+ * the whole chat without forking the SDK.
10
+ *
11
+ * BACKLOG 4.1.
12
+ *
13
+ * Adding a new token:
14
+ * 1. Add a field to `AppilotsThemeTokens` below.
15
+ * 2. Set a value in BOTH `defaultLight` and `defaultDark` (and ideally
16
+ * keep them visually consistent — e.g. dark text on light bg ↔
17
+ * light text on dark bg).
18
+ * 3. Use it in components via `useAppilotsTheme()`.
19
+ * 4. Mirror the field on `themeTokensSchema` in `@appilots/shared` if
20
+ * it should be settable from the dashboard.
21
+ *
22
+ * Removing a token is a breaking change — bump the SDK minor.
23
+ */
24
+ interface AppilotsThemeTokens {
25
+ /** Hex color values. The 8-digit form (#RRGGBBAA) is allowed. */
26
+ colors: {
27
+ /** Brand color — send button, FAB, header dot, links. */
28
+ primary: string;
29
+ /** Secondary brand accent — used sparingly (e.g. the human-agent/operator icon accent in message rows). */
30
+ secondary: string;
31
+ /** Page/modal background, behind the messages list. */
32
+ background: string;
33
+ /** Surface color for assistant message bubbles, input field, chips. */
34
+ surface: string;
35
+ /** Default text color (high contrast on background). */
36
+ text: string;
37
+ /** Muted text — placeholders, secondary labels, "Powered by". */
38
+ textSecondary: string;
39
+ /** 1px hairlines under header, around chips. */
40
+ border: string;
41
+ /** Success state — completed action checks in the breadcrumb (ActionBreadcrumb `success` tone). */
42
+ success: string;
43
+ /**
44
+ * Warning / caution state — drives the breadcrumb's `pending` tone
45
+ * (queued, not-yet-run actions). The default is a neutral gray, not
46
+ * amber, so it renders pixel-identical to the SDK's pre-4.2 hardcoded
47
+ * palette out of the box; set an amber/yellow here to make queued
48
+ * actions visually louder.
49
+ */
50
+ warning: string;
51
+ /** Error state — failed action rows (ActionBreadcrumb `failed` tone) and destructive badges/CTAs (confirm card, reject button). */
52
+ error: string;
53
+ /** Text color for chip/button labels (e.g. suggested prompts). */
54
+ buttonText: string;
55
+ /** Text color inside the assistant's message bubble (not the user's — that stays white on `primary`). */
56
+ bubbleText: string;
57
+ /**
58
+ * Text color inside the USER's message bubble (on `primary`). Optional
59
+ * mirror of `bubbleText` for the user side — falls back to white,
60
+ * matching the SDK's pre-4.2 hardcoded value, when unset.
61
+ */
62
+ userBubbleText: string;
63
+ };
64
+ typography: {
65
+ /** Font family applied to ALL chat text. Falls back to system. */
66
+ fontFamily: string;
67
+ fontSizeXs: number;
68
+ fontSizeSm: number;
69
+ fontSizeBase: number;
70
+ fontSizeLg: number;
71
+ };
72
+ radii: {
73
+ /** Tight corners — chips, small badges. */
74
+ sm: number;
75
+ /** Default — input field, send button, secondary buttons. */
76
+ md: number;
77
+ /** Generous — chat sheet, message bubbles. */
78
+ lg: number;
79
+ };
80
+ /** Optional drop-shadows (RN-shaped, applied via View style). */
81
+ shadows: {
82
+ /** Tells the developer's dark/light intent. Components don't read
83
+ * this directly — they read tokens — but `mode` is forwarded so
84
+ * status bar / image color choices can branch on it. */
85
+ appearance: 'light' | 'dark';
86
+ };
87
+ }
88
+ /**
89
+ * Default LIGHT theme — used when the device is in light mode and the
90
+ * developer hasn't overridden anything. Visually matches the SDK's
91
+ * pre-4.1 hardcoded palette so existing apps don't change look on
92
+ * upgrade.
93
+ */
94
+ declare const defaultLightTheme: AppilotsThemeTokens;
95
+ /**
96
+ * Default DARK theme — used when the device is in dark mode and the
97
+ * developer hasn't overridden anything. Picked to roughly mirror the
98
+ * light theme: same hue family, inverted background/text, slightly
99
+ * cooler border/surface tones.
100
+ */
101
+ declare const defaultDarkTheme: AppilotsThemeTokens;
102
+ /**
103
+ * Deep-partial of the token tree — what a developer hands to the SDK
104
+ * via the `theme` prop or dashboard config. Every field optional;
105
+ * unspecified fields fall through to the default.
106
+ */
107
+ type PartialThemeTokens = {
108
+ colors?: Partial<AppilotsThemeTokens['colors']>;
109
+ typography?: Partial<AppilotsThemeTokens['typography']>;
110
+ radii?: Partial<AppilotsThemeTokens['radii']>;
111
+ shadows?: Partial<AppilotsThemeTokens['shadows']>;
112
+ };
113
+ /**
114
+ * Merge a partial token tree on top of a base. Keys present in the
115
+ * partial win; missing keys keep the base value. Two levels deep is
116
+ * enough for the current token shape, so we don't need a generic deep
117
+ * merge — keeps tree-shaking friendly.
118
+ */
119
+ declare function mergeThemeTokens(base: AppilotsThemeTokens, partial?: PartialThemeTokens | null): AppilotsThemeTokens;
120
+
121
+ /**
122
+ * SDK locale code. Canonical source of truth for `AppilotsLocale` — moved
123
+ * here (out of the React Native-coupled `i18n/I18nProvider`) so that
124
+ * platform-agnostic contract types (`RemotePersonalization.defaultLocale`)
125
+ * don't pull in a React/React Native import just for a string union type.
126
+ *
127
+ * `@appilots/sdk`'s `i18n/I18nProvider.tsx` re-exports this type from its
128
+ * original public path (`@appilots/sdk`'s `./i18n` barrel) so nothing
129
+ * downstream of the SDK's public API changes.
130
+ *
131
+ * Adding a locale = adding a bundle file in `@appilots/sdk`'s
132
+ * `i18n/bundles/` AND a branch in `i18n/I18nProvider.tsx`'s `BUNDLES`
133
+ * map AND a variant here. BACKLOG 4.1.
134
+ */
135
+ type AppilotsLocale = 'pt-BR' | 'en' | 'es';
136
+
137
+ /**
138
+ * Core types for the Appilots SDK.
139
+ */
140
+
141
+ /**
142
+ * Payload of `GET /agent/personalization` — what the dev configured in
143
+ * the dashboard under Projects > Personalization. Fetched once on
144
+ * `AppilotsProvider` mount and applied by `AppilotsChat` as a fallback
145
+ * for any prop the dev did NOT set explicitly in code
146
+ * (prop > remote > SDK default).
147
+ *
148
+ * Only JSON-serializable values travel here: URLs/hex/booleans work,
149
+ * React nodes and local `require()` assets can only come via props.
150
+ * `null` means "not configured" — fall through to the next source.
151
+ */
152
+ interface RemotePersonalization {
153
+ assistantName: string | null;
154
+ /** Avatar URL shown next to assistant turns. */
155
+ assistantAvatar: string | null;
156
+ /** Emoji or image URL for the empty-state badge. */
157
+ emptyStateIcon: string | null;
158
+ welcomeMessage: string | null;
159
+ chatTitle: string | null;
160
+ poweredByVisible: boolean;
161
+ /**
162
+ * Partial token tree merged onto the SDK defaults. `mode` (when set)
163
+ * plays the role of the `themeMode` prop.
164
+ */
165
+ theme: (PartialThemeTokens & {
166
+ mode?: 'auto' | 'light' | 'dark';
167
+ }) | null;
168
+ defaultLocale: AppilotsLocale | null;
169
+ triggerButtonColor: string | null;
170
+ triggerButtonImageUrl: string | null;
171
+ }
172
+ type MessageRole = 'user' | 'assistant' | 'system' | 'human_agent';
173
+ interface ChatMessage {
174
+ id: string;
175
+ role: MessageRole;
176
+ content: string;
177
+ timestamp: number;
178
+ metadata?: Record<string, unknown>;
179
+ }
180
+ interface AppilotsTraceEntry {
181
+ id: string;
182
+ timestamp: number;
183
+ type: AppilotsEventType | 'agent:trace';
184
+ messageId?: string;
185
+ actionId?: string;
186
+ actionType?: AgentActionType | string;
187
+ status?: AgentAction['status'] | 'started' | 'error';
188
+ summary?: string;
189
+ data: Record<string, unknown>;
190
+ }
191
+ interface AgentMessage extends ChatMessage {
192
+ role: 'assistant';
193
+ actions?: AgentAction[];
194
+ thinking?: string;
195
+ }
196
+ type AgentActionType = 'navigate' | 'form_fill' | 'ui_interaction' | 'scroll_list' | 'confirm' | 'custom';
197
+ interface AgentAction {
198
+ id: string;
199
+ type: AgentActionType;
200
+ payload: NavigationPayload | FormFillPayload | UIInteractionPayload | ScrollListPayload | Record<string, unknown>;
201
+ status: 'pending' | 'executing' | 'completed' | 'failed';
202
+ error?: string;
203
+ /** ID of the assistant message that triggered this action */
204
+ messageId?: string;
205
+ /**
206
+ * BACKLOG 2.2 — When the server flags an action as destructive,
207
+ * the SDK renders any preceding `confirm` action with the danger
208
+ * variant and expects the action to be gated by user approval.
209
+ */
210
+ destructive?: boolean;
211
+ }
212
+ interface NavigationPayload {
213
+ screenName: string;
214
+ params?: Record<string, unknown>;
215
+ navigationAction: 'push' | 'navigate' | 'replace' | 'goBack' | 'reset';
216
+ /**
217
+ * Optional path of parent navigator route names for nested screens.
218
+ * E.g. ['HomeTab', 'VehiclesTab'] to reach a screen inside
219
+ * HomeTab → VehiclesTab → screenName.
220
+ *
221
+ * React Navigation requires nested navigation params:
222
+ * nav.navigate('HomeTab', { screen: 'VehiclesTab', params: { screen: 'VehicleCreate' } })
223
+ *
224
+ * The AI model provides this based on the MCP document's navigation graph.
225
+ */
226
+ path?: string[];
227
+ }
228
+ interface FormFillPayload {
229
+ screenName: string;
230
+ fields: FormFieldAction[];
231
+ /**
232
+ * If true, the handler presses the screen's primary submit button
233
+ * after all fields are filled. The submit button is resolved via
234
+ * `registerScreen({ actions: [{ type: 'submit', ... }] })` first,
235
+ * then via the fiber tree and a label heuristic.
236
+ *
237
+ * Aligned with the `submitAfterFill` field in the LLM tool schema
238
+ * (`agentTools.form_fill` in ai-relay.ts).
239
+ */
240
+ submitAfterFill?: boolean;
241
+ }
242
+ interface FormFieldAction {
243
+ fieldId: string;
244
+ fieldType: 'text' | 'select' | 'toggle' | 'date' | 'number' | 'custom';
245
+ value: unknown;
246
+ label?: string;
247
+ }
248
+ interface UIInteractionPayload {
249
+ componentId: string;
250
+ /** Canonical server/LLM identifier. `componentId` is kept as SDK alias. */
251
+ targetId?: string;
252
+ action: 'press' | 'longPress' | 'scroll' | 'swipe' | 'focus' | 'set_value';
253
+ /**
254
+ * Numeric value for `set_value` (sliders / adjustable controls).
255
+ * The handler clamps to the slider's [min, max] and snaps to its step.
256
+ */
257
+ value?: number;
258
+ params?: Record<string, unknown>;
259
+ }
260
+ /**
261
+ * Scroll a list/collection so virtualized off-screen rows mount and
262
+ * show up in the next observation. Mirrors `scrollListPayloadSchema`
263
+ * in @appilots/shared. At least one of the fields should be present;
264
+ * the handler falls back to paging one viewport down when only a
265
+ * listId is given.
266
+ */
267
+ interface ScrollListPayload {
268
+ /** Runtime list id from the observation's "Lists visible" block. */
269
+ listId?: string;
270
+ /** 1-based index in the list's DATA to scroll to. */
271
+ toIndex?: number;
272
+ /** Coarse paging when no target index is known. */
273
+ direction?: 'up' | 'down';
274
+ }
275
+ interface AgentPermissions {
276
+ canNavigate: boolean;
277
+ canFillForms: boolean;
278
+ canInteractUI: boolean;
279
+ canSubmitForms: boolean;
280
+ allowedScreens?: string[];
281
+ blockedScreens?: string[];
282
+ allowedActions?: AgentActionType[];
283
+ }
284
+ type AppilotsEventType = 'agent:action:start' | 'agent:action:complete' | 'agent:action:error' | 'agent:message' | 'navigation:change' | 'chat:open' | 'chat:close' | 'chat:escalation:start' | 'chat:escalation:message' | 'chat:escalation:end';
285
+ interface AppilotsEvent {
286
+ type: AppilotsEventType;
287
+ timestamp: number;
288
+ data: Record<string, unknown>;
289
+ }
290
+ type AppilotsEventHandler = (event: AppilotsEvent) => void;
291
+ /**
292
+ * Client-side view of an open escalation. `resolved` never appears
293
+ * here — resolution clears the state (after surfacing a system
294
+ * message in the transcript).
295
+ */
296
+ interface EscalationState {
297
+ id: string;
298
+ status: 'pending' | 'active';
299
+ /** Set once an operator claims the conversation. */
300
+ operatorName?: string;
301
+ }
302
+
303
+ interface AppilotsClientOptions {
304
+ projectId: string;
305
+ apiBaseUrl?: string;
306
+ apiKey?: string;
307
+ debug?: boolean;
308
+ timeout?: number;
309
+ headers?: Record<string, string>;
310
+ /**
311
+ * Version of the MCP doc bundled with this app build. The server
312
+ * compares this against the currently-active MCP doc for the
313
+ * project and emits a `mcp_version_mismatch` telemetry event when
314
+ * they differ — the canonical sign that the dev shipped an app
315
+ * update but forgot to regenerate/upload the MCP.
316
+ *
317
+ * Tip: import this from the MCP file the CLI generates, or read it
318
+ * from your app's package.json so it stays in lockstep with releases.
319
+ */
320
+ mcpVersion?: string;
321
+ /**
322
+ * The host app's version (e.g. from package.json or
323
+ * react-native-device-info). Sent as `X-App-Version` on every request
324
+ * so the server can match the compatible MCP document per app build —
325
+ * essential for OTA-updated fleets where multiple app versions coexist.
326
+ */
327
+ appVersion?: string;
328
+ /**
329
+ * Who the app's current user is. `id` becomes the session's
330
+ * externalUserId; `name`/`identifiers` are upserted into the
331
+ * workspace's end-users registry (fire-and-forget identify after the
332
+ * session opens) so support operators see a person, not an anonymous
333
+ * id. Identifiers are dashboard-only — never sent to the LLM.
334
+ */
335
+ user?: AppilotsUser;
336
+ }
337
+ interface AppilotsUser {
338
+ /** The app's own user id (matches your backend). */
339
+ id: string;
340
+ name?: string;
341
+ /** Free-form lookup keys: { email, phone, cpf, ... }. Max 10. */
342
+ identifiers?: Record<string, string>;
343
+ }
344
+ interface SendMessageResponse {
345
+ sessionId: string;
346
+ message: ChatMessage;
347
+ /** Summary message to show AFTER actions complete */
348
+ summaryMessage?: ChatMessage;
349
+ actions?: AgentAction[];
350
+ usage?: {
351
+ tokensUsed: number;
352
+ modelUsed: string;
353
+ latencyMs: number;
354
+ };
355
+ }
356
+ interface SendMessageStreamOptions {
357
+ /**
358
+ * Fired per SSE text-delta with the chunk and the accumulated text so
359
+ * far — render `fullText` directly; chunks may split words/markdown.
360
+ */
361
+ onTextDelta?: (chunk: string, fullText: string) => void;
362
+ /** Fired once when the server announces the session id. */
363
+ onSession?: (sessionId: string) => void;
364
+ /** Abort mid-generation (stop button). Rejects with name='AbortError'. */
365
+ signal?: AbortSignal;
366
+ }
367
+ /** Runtime context sent with every user message. */
368
+ interface SendMessageContext {
369
+ /**
370
+ * Which client platform this observation came from — `'react-native'`,
371
+ * `'web'`, `'android'`, `'ios'`, or any other client-defined string.
372
+ * The server treats an absent value as `'react-native'` (see
373
+ * `docs/agent-contract.md`'s "The `platform` field" section), so
374
+ * setting it is optional but forward-compatible: a client that sends
375
+ * it explicitly isn't relying on that default staying `'react-native'`
376
+ * forever.
377
+ */
378
+ platform?: string;
379
+ currentScreen?: string;
380
+ formState?: Record<string, unknown>;
381
+ /** Design-time screen metadata from registerScreen() or the MCP doc */
382
+ screenMetadata?: Record<string, unknown>;
383
+ /** Runtime React Navigation summary captured by the SDK */
384
+ navigationState?: {
385
+ currentRouteName?: string;
386
+ activePath?: string[];
387
+ rootRouteNames?: string[];
388
+ currentRouteNames?: string[];
389
+ routeNames?: string[];
390
+ canGoBack?: boolean;
391
+ };
392
+ /** Runtime snapshot from captureSnapshot() — what's actually visible */
393
+ snapshot?: Record<string, unknown>;
394
+ /** Legacy registry snapshot — kept as a fallback signal */
395
+ registeredComponents?: Array<{
396
+ id: string;
397
+ kind: 'field' | 'target' | 'toggle';
398
+ screen?: string;
399
+ label?: string;
400
+ }>;
401
+ /** Runtime list registry snapshot — collection metadata even when rows are virtualized. */
402
+ registeredLists?: Array<{
403
+ kind: 'list';
404
+ id: string;
405
+ component: string;
406
+ itemCount?: number;
407
+ label?: string;
408
+ screen?: string;
409
+ refreshing?: boolean;
410
+ empty?: boolean;
411
+ }>;
412
+ }
413
+ declare class AppilotsClient {
414
+ private readonly baseUrl;
415
+ private readonly projectId;
416
+ private readonly headers;
417
+ private readonly timeout;
418
+ private readonly debug;
419
+ private readonly mcpVersion;
420
+ private readonly user;
421
+ private sessionId;
422
+ /** Guard so identify fires at most once per client instance. */
423
+ private identified;
424
+ constructor(options: AppilotsClientOptions);
425
+ private log;
426
+ private describeNonJsonResponse;
427
+ private request;
428
+ createSession(userId?: string, deviceInfo?: Record<string, unknown>): Promise<string>;
429
+ /**
430
+ * Upsert the configured user into the end-users registry. Fires once
431
+ * per client, after the first session opens; fire-and-forget — a
432
+ * failed identify must never break the chat.
433
+ */
434
+ private identifyConfiguredUser;
435
+ destroySession(): Promise<void>;
436
+ getSessionId(): string | null;
437
+ sendMessage(content: string, context?: SendMessageContext): Promise<SendMessageResponse>;
438
+ /**
439
+ * Streaming variant of `sendMessage` — consumes the server's SSE
440
+ * endpoint (`/agent/message/stream`) and fires `onTextDelta` per chunk
441
+ * so the UI can render tokens as they arrive (OKR-008 KR1). Resolves
442
+ * with the same `SendMessageResponse` shape once the `done` event lands.
443
+ *
444
+ * Uses XMLHttpRequest because React Native's fetch does not expose
445
+ * `response.body` for incremental reads; RN's XHR delivers progressive
446
+ * `responseText`, which is the standard SSE transport on RN.
447
+ *
448
+ * Errors:
449
+ * - `StreamTransportError` — transport failed before ANY event; safe
450
+ * for the caller to fall back to the non-streaming endpoint.
451
+ * - `StreamAbortError` (name='AbortError') — options.signal fired;
452
+ * carries `partialContent` so the UI can keep what streamed.
453
+ */
454
+ sendMessageStream(content: string, context?: SendMessageContext, options?: SendMessageStreamOptions): Promise<SendMessageResponse>;
455
+ continueAgent(results: Array<{
456
+ actionId: string;
457
+ type: string;
458
+ success: boolean;
459
+ error?: string;
460
+ summary?: string;
461
+ /** BACKLOG 3.2 — structured failure diagnose, server uses for recovery */
462
+ diagnose?: {
463
+ category: 'component-not-found' | 'disabled' | 'validation' | 'network-5xx' | 'network-4xx' | 'screen-timeout' | 'ambiguous-target' | 'unknown';
464
+ visibleMessage?: string;
465
+ fieldId?: string;
466
+ targetId?: string;
467
+ screen?: string;
468
+ httpStatus?: number;
469
+ /** Candidate ids when resolution failed due to ambiguity. */
470
+ candidates?: string[];
471
+ recoverable?: boolean;
472
+ requiresUserInput?: boolean;
473
+ };
474
+ /** BACKLOG 3.2 — how many times this fingerprint has been retried (1 = first retry). */
475
+ recoveryAttempt?: number;
476
+ /** BACKLOG 3.2 — set when SDK has hit the per-action retry cap. */
477
+ recoveryExhausted?: boolean;
478
+ /**
479
+ * Set when a handler reported success but the expected visible
480
+ * side-effect did not happen, e.g. navigate returned but route stayed.
481
+ */
482
+ toolWithoutEffect?: boolean;
483
+ effect?: 'unknown' | 'none' | 'partial' | 'changed' | 'completed';
484
+ userVisibleStatusKey?: string;
485
+ }>, context: Record<string, unknown>, hop: number): Promise<SendMessageResponse & {
486
+ isDone: boolean;
487
+ hop: number;
488
+ }>;
489
+ executeAction(actionId: string): Promise<AgentAction>;
490
+ /**
491
+ * Rewrite an action's type when the AI used a semantically-misclassified
492
+ * action type. The most common case: the LLM emits
493
+ * { type: 'ui_interaction', payload: { action: 'select', targetId, value } }
494
+ * to mean "set this field's value", which is really a form_fill. We detect
495
+ * that here and convert it before normalization, so the executor sees the
496
+ * right action shape and the field's setValue() is called instead of a
497
+ * meaningless press on a non-pressable component.
498
+ */
499
+ private rewriteActionTypeIfNeeded;
500
+ /**
501
+ * Normalize API tool call payloads to match SDK's expected payload types.
502
+ * The AI model may return slightly different field names than what the
503
+ * SDK executor expects, and may use vocabulary (e.g. "select", "scroll_to",
504
+ * "open") that the SDK doesn't natively support — we remap those to the
505
+ * nearest equivalent here so the executor never sees an "unknown action".
506
+ */
507
+ private normalizePayload;
508
+ /**
509
+ * Legacy per-action status report. The agentic chat loop reports via
510
+ * `continueAgent` (which carries diagnose + a fresh snapshot); this
511
+ * endpoint remains for apps driving actions manually through
512
+ * `useAppilotsActions`. `diagnose` is forwarded when provided so even
513
+ * the legacy path gives the server a failure category.
514
+ */
515
+ completeAction(actionId: string, success: boolean, error?: string, diagnose?: Record<string, unknown>): Promise<void>;
516
+ /**
517
+ * Fetch actions the server has persisted but that haven't been
518
+ * completed yet. Use after an SSE drop or a hard error to recover
519
+ * the batch without losing the actions the model already decided.
520
+ *
521
+ * Returns an empty array if there are no pending actions or if the
522
+ * call fails — never throws.
523
+ */
524
+ recoverPendingActions(sessionId?: string): Promise<AgentAction[]>;
525
+ /**
526
+ * Fetch dev-defined and empirically-popular prompts to seed the chat
527
+ * empty-state with one-tap chips. Cheap (cached server-side for 1h) but
528
+ * still a network hit, so callers should debounce around chat-open.
529
+ *
530
+ * @param screen Optional — when provided, response includes screen-scoped
531
+ * popular prompts in addition to globals.
532
+ */
533
+ getPopularPrompts(screen?: string, limit?: number): Promise<{
534
+ devDefined: string[];
535
+ screenPopular: string[];
536
+ globalPopular: string[];
537
+ computedAt: string;
538
+ }>;
539
+ /**
540
+ * Fetch the project's dashboard-configured personalization (theme,
541
+ * branding, FAB color/image, locale...). Called by `AppilotsProvider`
542
+ * once on mount — cheap (cached server-side for 1h) and applied by
543
+ * `AppilotsChat` as a fallback for props not set explicitly in code.
544
+ *
545
+ * Throws on network/HTTP failure — the provider treats any failure as
546
+ * "no remote config" and stays on props/defaults.
547
+ */
548
+ getPersonalization(): Promise<RemotePersonalization>;
549
+ /**
550
+ * Ask for a human operator. Idempotent: if the session already has
551
+ * an open escalation the server returns it instead of creating a
552
+ * duplicate. Creates the session first when the chat had none yet
553
+ * (the server sends it back and we adopt it, so the whole
554
+ * conversation stays under one sessionId).
555
+ */
556
+ requestEscalation(reason: 'user_requested' | 'agent_gave_up', note?: string): Promise<{
557
+ escalationId: string;
558
+ status: 'pending' | 'active';
559
+ }>;
560
+ /**
561
+ * Tell the server the user walked away from the conversation (chat
562
+ * cleared) so the escalation is closed instead of leaving the
563
+ * operator talking to nobody. Fire-and-forget: never throws — the
564
+ * local cleanup must proceed even if the network is gone.
565
+ */
566
+ abandonEscalation(escalationId: string): Promise<void>;
567
+ /** User message routed to the human operator (no LLM involved). */
568
+ sendEscalationMessage(escalationId: string, content: string): Promise<void>;
569
+ /**
570
+ * Poll fallback / reconnect catch-up: status + operator messages
571
+ * created after `since` (ISO timestamp of the last one we have).
572
+ */
573
+ getEscalationUpdates(escalationId: string, since?: string): Promise<{
574
+ status: 'pending' | 'active' | 'resolved';
575
+ messages: Array<{
576
+ id: string;
577
+ content: string;
578
+ createdAt: string;
579
+ }>;
580
+ }>;
581
+ /**
582
+ * Open the escalation SSE channel — operator replies + status
583
+ * changes pushed live. Same XHR transport as `sendMessageStream`
584
+ * (RN's fetch can't read a body incrementally).
585
+ *
586
+ * Long-lived by design: no idle watchdog — the server pings every
587
+ * 25s, and a genuinely dead connection surfaces as `onClose`, which
588
+ * the hook answers with a backoff reconnect + `since` catch-up.
589
+ * Returns a close function; closing never fires `onClose`.
590
+ */
591
+ openEscalationStream(escalationId: string, handlers: {
592
+ since?: string;
593
+ onHumanMessage: (message: {
594
+ id: string;
595
+ content: string;
596
+ createdAt: string;
597
+ }) => void;
598
+ onStatus: (status: 'pending' | 'active' | 'resolved', operatorName?: string) => void;
599
+ /** Transport ended (error or server close) — caller decides on reconnect. */
600
+ onClose: () => void;
601
+ }): () => void;
602
+ }
603
+
604
+ /**
605
+ * Snapshot types — the platform-agnostic "view model" of what the user
606
+ * is currently seeing on screen, sent to the AI agent so it has
607
+ * accurate visible state.
608
+ *
609
+ * Every platform walker (React Native fiber walk, web DOM walk, ...)
610
+ * produces this same shape; the wire contract it feeds is
611
+ * `agentSnapshotSchema` in `@appilots/shared`.
612
+ */
613
+ interface InputSnapshot {
614
+ /** Best identifier — testID/data-testid, accessibilityLabel/aria-label, or placeholder */
615
+ id?: string;
616
+ /** Human-readable label inferred from accessibility metadata or sibling text */
617
+ label?: string;
618
+ /** Current value (only present for controlled inputs) */
619
+ value?: string;
620
+ /** Placeholder text */
621
+ placeholder?: string;
622
+ /** Whether the input is editable */
623
+ editable?: boolean;
624
+ /** Whether the input is secure (password field) */
625
+ secure?: boolean;
626
+ /** Inferred type based on the platform's input-type metadata */
627
+ type?: 'text' | 'email' | 'number' | 'phone' | 'password';
628
+ /**
629
+ * True when this input lives inside a currently-visible modal. When a
630
+ * modal is open, only inModal elements can actually receive input —
631
+ * everything else is behind the overlay.
632
+ */
633
+ inModal?: boolean;
634
+ }
635
+ interface ButtonSnapshot {
636
+ /** Best identifier — testID/data-testid, accessibilityLabel/aria-label, or inferred from child text */
637
+ id?: string;
638
+ /** Human-readable label — usually the visible text inside the button */
639
+ label?: string;
640
+ /** Whether the button is disabled */
641
+ disabled?: boolean;
642
+ /**
643
+ * Whether the button currently appears selected/active — set by
644
+ * grouped, mutually-exclusive controls (segmented controls, radio
645
+ * groups) where each option is its own pressable target.
646
+ */
647
+ selected?: boolean;
648
+ /** True when this button lives inside a currently-visible modal. */
649
+ inModal?: boolean;
650
+ }
651
+ interface ToggleSnapshot {
652
+ /** Best identifier */
653
+ id?: string;
654
+ /** Human-readable label */
655
+ label?: string;
656
+ /** Current on/off state */
657
+ value?: boolean;
658
+ /** True when this toggle lives inside a currently-visible modal. */
659
+ inModal?: boolean;
660
+ }
661
+ interface SliderSnapshot {
662
+ /** Registry id — the executable handle. */
663
+ id?: string;
664
+ /** Human-readable label */
665
+ label?: string;
666
+ /** Current numeric value */
667
+ value?: number;
668
+ /** Lower bound the executor clamps to */
669
+ min?: number;
670
+ /** Upper bound the executor clamps to */
671
+ max?: number;
672
+ /** Step the executor snaps to (omitted = continuous) */
673
+ step?: number;
674
+ /** Whether the slider is currently disabled */
675
+ disabled?: boolean;
676
+ /** True when this slider lives inside a currently-visible modal. */
677
+ inModal?: boolean;
678
+ }
679
+ interface ListItemSnapshot {
680
+ /** 1-indexed position within the parent list (matches "selecione o terceiro"). */
681
+ index: number;
682
+ /**
683
+ * 0-based index of this row in the list's backing DATA, when known.
684
+ * For scrolled/virtualized lists this differs from `index`.
685
+ */
686
+ dataIndex?: number;
687
+ /** Framework key of the row, if present (typically the item's domain id). */
688
+ reactKey?: string;
689
+ /** Runtime key supplied by list tracking, if available. */
690
+ itemKey?: string;
691
+ /** Texts captured from this item's subtree, preserving row association. */
692
+ texts: string[];
693
+ /** Buttons inside this item — e.g. an inline "Edit" button on a row. */
694
+ buttons: ButtonSnapshot[];
695
+ /** Inputs inside this item — rare but possible (inline edit row). */
696
+ inputs: InputSnapshot[];
697
+ /** Toggles inside this item. */
698
+ toggles: ToggleSnapshot[];
699
+ /**
700
+ * Synthetic id assigned by the walker. Stable within a single
701
+ * snapshot; format `list-<L>-item-<I>` (0-indexed L, 1-indexed I).
702
+ * Used by tap-by-ordinal resolution in the executor.
703
+ */
704
+ syntheticId: string;
705
+ }
706
+ interface ListSnapshot {
707
+ /** 0-indexed list ordinal — multiple lists on one screen get 0, 1, 2... */
708
+ index: number;
709
+ /** Runtime list id when tracking or explicit props provide one. */
710
+ id?: string;
711
+ /** The container component/tag name as observed by the walker. */
712
+ containerType: string;
713
+ /**
714
+ * Source that identified this list. `'fiber'`/`'auto-tracked'` are
715
+ * the walker's own discovery tags (a DOM walker reports
716
+ * `'auto-tracked'` for app-annotated lists and omits the field for
717
+ * heuristically-detected ones); `'registry'` means the list came
718
+ * from the SDK's list registry rather than the tree walk.
719
+ */
720
+ source?: 'fiber' | 'auto-tracked' | 'registry';
721
+ /** Total data-set count when the list exposes it. */
722
+ itemCount?: number;
723
+ /** Number of row items captured in this snapshot. */
724
+ visibleItemCount?: number;
725
+ /** True when the list reports a refresh/loading state. */
726
+ refreshing?: boolean;
727
+ /** True when total item count is known and zero. */
728
+ empty?: boolean;
729
+ /** Human-readable label if the app supplied one. */
730
+ label?: string;
731
+ /** Items in visible order. */
732
+ items: ListItemSnapshot[];
733
+ /**
734
+ * Lightweight text projection of the list's FULL data set (capped),
735
+ * so the agent can see/search rows that virtualization keeps
736
+ * unmounted. Each entry: 0-based data index, stable key, short text.
737
+ */
738
+ dataPreview?: ListDataPreviewEntry[];
739
+ /** Current vertical scroll offset in px, when readable. */
740
+ scrollOffsetY?: number;
741
+ /** True when there is scrollable content above the viewport. */
742
+ canScrollUp?: boolean;
743
+ /** True when there is scrollable content below the viewport. */
744
+ canScrollDown?: boolean;
745
+ }
746
+ interface ListDataPreviewEntry {
747
+ /** 0-based index in the list's backing data. */
748
+ index: number;
749
+ /** Stable key from the item's domain id when available. */
750
+ key?: string;
751
+ /** Short human-readable projection of the item (capped length). */
752
+ text: string;
753
+ }
754
+ interface ChoiceOptionSnapshot {
755
+ /** 1-indexed option position within this group. */
756
+ index: number;
757
+ /** Stable-enough id for the current snapshot/action turn. */
758
+ syntheticId: string;
759
+ /** Best target id if this option is backed by a pressable component. */
760
+ targetId?: string;
761
+ /** Human-readable option label. */
762
+ label?: string;
763
+ /** Text segments that belong to this option. */
764
+ texts: string[];
765
+ /** Whether this option appears selected. */
766
+ selected?: boolean;
767
+ /** Whether this option appears disabled. */
768
+ disabled?: boolean;
769
+ }
770
+ interface ChoiceGroupSnapshot {
771
+ /** 0-indexed group ordinal on the current screen. */
772
+ index: number;
773
+ /** Runtime id when known, usually inherited from a list/collection. */
774
+ id?: string;
775
+ /** Human-readable label when known. */
776
+ label?: string;
777
+ /** Source that produced this choice group. */
778
+ source?: 'list' | 'buttons' | 'heuristic';
779
+ /** Visible options in order. */
780
+ options: ChoiceOptionSnapshot[];
781
+ }
782
+ interface InteractionElementListContext {
783
+ listIndex?: number;
784
+ listId?: string;
785
+ listLabel?: string;
786
+ itemIndex?: number;
787
+ itemKey?: string;
788
+ reactKey?: string;
789
+ syntheticId?: string;
790
+ }
791
+ interface InteractionElementSnapshot {
792
+ /** Stable id for the current screen/content, preferred for tool calls. */
793
+ id: string;
794
+ /** Semantic UI role. */
795
+ role: 'option' | 'button' | 'input' | 'toggle' | 'slider' | 'listItem';
796
+ /** Human-readable label. */
797
+ label?: string;
798
+ /** Text segments associated with this element. */
799
+ texts: string[];
800
+ /** Actions supported by this element. */
801
+ actions: Array<'press' | 'focus' | 'toggle' | 'setValue'>;
802
+ /** Whether the element is currently disabled. */
803
+ disabled?: boolean;
804
+ /** Whether the element appears selected. */
805
+ selected?: boolean;
806
+ /** Source that produced the element. */
807
+ source?: 'list' | 'button' | 'input' | 'toggle' | 'slider' | 'choice';
808
+ /** Legacy/fallback target id, if any. */
809
+ targetId?: string;
810
+ /** Context for row/list options. */
811
+ listContext?: InteractionElementListContext;
812
+ /**
813
+ * True when the underlying component lives inside a currently-visible
814
+ * modal — the only targets actually touchable while the overlay is up.
815
+ */
816
+ inModal?: boolean;
817
+ }
818
+ interface ScreenSnapshot {
819
+ /** The currently active route name, if known */
820
+ route: string | null;
821
+ /** All visible static text */
822
+ texts: string[];
823
+ /** All text inputs currently rendered (and visible) */
824
+ inputs: InputSnapshot[];
825
+ /** All button-like components */
826
+ buttons: ButtonSnapshot[];
827
+ /** All toggle components */
828
+ toggles: ToggleSnapshot[];
829
+ /** Sliders / adjustable numeric controls. */
830
+ sliders: SliderSnapshot[];
831
+ /** Whether a loading indicator is visible */
832
+ loading: boolean;
833
+ /** Whether a modal is currently open */
834
+ modalOpen: boolean;
835
+ /**
836
+ * Lists detected in the visible tree. Each list's items have their
837
+ * own per-item texts/buttons/inputs/toggles, NOT duplicated in the
838
+ * flat top-level arrays — preserving the row association the flat
839
+ * shape destroys.
840
+ */
841
+ lists: ListSnapshot[];
842
+ /**
843
+ * Choice groups detected from visible cards/rows/chips/buttons, used
844
+ * for select-like flows where no text input exists.
845
+ */
846
+ choiceGroups: ChoiceGroupSnapshot[];
847
+ /**
848
+ * Interaction graph: visible actionable elements with stable ids,
849
+ * semantic roles, labels, and execution fallbacks. Agents should
850
+ * prefer these ids over synthetic ordinal handles.
851
+ */
852
+ elements: InteractionElementSnapshot[];
853
+ /** Diagnostic counts for debugging */
854
+ stats?: {
855
+ visitedFibers: number;
856
+ skippedHidden: number;
857
+ };
858
+ }
859
+ /**
860
+ * Localized copy for escalation system messages, injected by the chat
861
+ * surface (the machine has no i18n access — same pattern as errorPrefix).
862
+ * When omitted, no system messages are appended but the state machine
863
+ * still works.
864
+ */
865
+ interface EscalationStrings {
866
+ /** Appended right after the escalation is created. */
867
+ requested: string;
868
+ /** Appended when an operator claims the conversation. */
869
+ connected: string;
870
+ /** Appended when the operator resolves — AI takes over again. */
871
+ resolved: string;
872
+ /** Content of the offer chip message appended when the agent gives up. */
873
+ offer: string;
874
+ }
875
+
876
+ type TraceListener = (entries: AppilotsTraceEntry[]) => void;
877
+ declare function recordAppilotsDebugTrace(entry: Omit<AppilotsTraceEntry, 'id'> & {
878
+ id?: string;
879
+ }): void;
880
+ declare function getAppilotsDebugTraces(): AppilotsTraceEntry[];
881
+ declare function clearAppilotsDebugTraces(): void;
882
+ declare function subscribeAppilotsDebugTraces(listener: TraceListener): () => void;
883
+
884
+ /**
885
+ * Human-readable labels and error messages for the action breadcrumb.
886
+ *
887
+ * Strings are PT-BR hardcoded for now. i18n is planned for backlog item
888
+ * 4.1 (Personalização) — when that lands, these strings move into the
889
+ * locale bundles.
890
+ *
891
+ * Two responsibilities:
892
+ * 1. `describeAction(action)` — turns a typed AgentAction into a label
893
+ * that varies by lifecycle state (pending/running/done/failed).
894
+ * 2. `humanizeError(raw, action)` — sanitises the raw error string from
895
+ * the executor into a short user-facing reason. Stack traces and
896
+ * protocol errors are collapsed into "algo deu errado" so users
897
+ * aren't shown technical noise.
898
+ */
899
+
900
+ type BreadcrumbState = 'pending' | 'running' | 'success' | 'failed';
901
+ interface BreadcrumbItem {
902
+ /** What to render on the line. */
903
+ label: string;
904
+ /** Lifecycle state — drives icon + colour in the breadcrumb. */
905
+ state: BreadcrumbState;
906
+ }
907
+ /**
908
+ * Map an AgentAction + its current status to a breadcrumb item ready to
909
+ * render. The function is intentionally defensive — both the native-tools
910
+ * and JSON-fallback code paths feed actions through here, and the JSON
911
+ * path is loose with payload shapes, so every field access has to assume
912
+ * `unknown`.
913
+ */
914
+ declare function describeAction(action: AgentAction): BreadcrumbItem;
915
+ /**
916
+ * Convert the executor's raw error string into a short, user-facing
917
+ * reason that fits inside parentheses on the breadcrumb line. Returns
918
+ * `undefined` when there's no useful information to show — caller can
919
+ * then drop the parenthetical entirely.
920
+ *
921
+ * Heuristics:
922
+ * - Apply known-pattern rewrites (rejected, not found, network, etc.)
923
+ * - If the result looks technical (stack frame, HTTP status, JSON
924
+ * dump) or is suspiciously long, fall back to "algo deu errado".
925
+ * - Trim and lowercase the first letter so it reads naturally inside
926
+ * the parens after the action verb.
927
+ */
928
+ declare function humanizeError(raw: string | undefined, _action?: AgentAction): string | undefined;
929
+
930
+ /**
931
+ * SDK version — bumped by changesets on release. Lives in its own module
932
+ * so runtime code (AppilotsClient) can import it without pulling the whole
933
+ * public barrel in and creating an import cycle.
934
+ */
935
+ declare const SDK_VERSION = "0.1.0";
936
+
937
+ interface AppilotsConfig {
938
+ /** Project ID from the Appilots dashboard */
939
+ projectId: string;
940
+ /** API base URL (defaults to Appilots cloud) */
941
+ apiBaseUrl?: string;
942
+ /** SDK API key (ak_...) for authenticating with the backend */
943
+ apiKey?: string;
944
+ /** Agent permissions for this app instance */
945
+ permissions?: AgentPermissions;
946
+ /** Enable debug logging */
947
+ debug?: boolean;
948
+ /**
949
+ * Host app version (e.g. package.json version). Forwarded to the API
950
+ * as `X-App-Version` so the server can serve the MCP document matching
951
+ * this app build (OTA fleets run several versions at once).
952
+ */
953
+ appVersion?: string;
954
+ /** Version of the MCP doc bundled with this build (stale-doc telemetry). */
955
+ mcpVersion?: string;
956
+ /**
957
+ * Who the app's current user is. Sessions carry `user.id` as
958
+ * externalUserId, and name/identifiers are upserted into the
959
+ * end-users registry so the support queue shows a person instead of
960
+ * "Usuário anônimo". Identifiers never reach the LLM.
961
+ */
962
+ user?: AppilotsUser;
963
+ /**
964
+ * Fetch the dashboard-configured personalization (theme, branding,
965
+ * FAB color, locale...) once on provider mount and apply it as a
966
+ * fallback for AppilotsChat props not set explicitly in code.
967
+ *
968
+ * Set to `false` to opt out — this is the SDK's only automatic
969
+ * network call before the user interacts, so apps with strict
970
+ * network/privacy posture can keep today's 100%-manual behavior.
971
+ * @default true
972
+ */
973
+ fetchPersonalization?: boolean;
974
+ }
975
+ interface AppilotsProviderProps {
976
+ /**
977
+ * SDK config. If omitted, auto-loads from `.appilotsrc` via the Metro
978
+ * resolver (requires `withAppilots()` in metro.config.js).
979
+ */
980
+ config?: AppilotsConfig;
981
+ children: React__default.ReactNode;
982
+ /** Optional custom client instance (if not provided, one is auto-created from config) */
983
+ client?: AppilotsClient;
984
+ }
985
+ interface AppilotsContextValue {
986
+ config: AppilotsConfig;
987
+ client: AppilotsClient;
988
+ subscribe: (handler: AppilotsEventHandler) => () => void;
989
+ emit: (event: AppilotsEvent) => void;
990
+ /**
991
+ * Dashboard-configured personalization fetched on mount. `null` until
992
+ * the fetch resolves — and forever, if it fails or is opted out
993
+ * (`fetchPersonalization: false`). Consumers must treat `null` as
994
+ * "use props/defaults"; the chat renders immediately with defaults
995
+ * and re-renders once this lands (accepted cold-start flash).
996
+ */
997
+ remotePersonalization: RemotePersonalization | null;
998
+ }
999
+ declare function AppilotsProvider({ config: configProp, children, client: externalClient }: AppilotsProviderProps): React__default.JSX.Element;
1000
+ declare function useAppilotsContext(): AppilotsContextValue;
1001
+
1002
+ /**
1003
+ * Convenience hook that combines all Appilots hooks into a single return value.
1004
+ *
1005
+ * @example
1006
+ * ```tsx
1007
+ * const { messages, sendMessage, currentScreen, pendingActions } = useAppilots();
1008
+ * ```
1009
+ */
1010
+ declare function useAppilots(): {
1011
+ config: AppilotsConfig;
1012
+ client: AppilotsClient;
1013
+ messages: ChatMessage[];
1014
+ isLoading: boolean;
1015
+ error: string | null;
1016
+ sendMessage: (content: string) => Promise<void>;
1017
+ clearMessages: () => void;
1018
+ clearError: () => void;
1019
+ currentScreen: string | null;
1020
+ navigationHistory: string[];
1021
+ setCurrentScreen: (screenName: string) => void;
1022
+ navigationRef: React$1.MutableRefObject<any>;
1023
+ pendingActions: AgentAction[];
1024
+ executingActions: AgentAction[];
1025
+ completedActions: AgentAction[];
1026
+ approveAction: (actionId: string) => Promise<boolean>;
1027
+ rejectAction: (actionId: string) => Promise<void>;
1028
+ };
1029
+
1030
+ interface UseAppilotsNavigationReturn {
1031
+ currentScreen: string | null;
1032
+ navigationHistory: string[];
1033
+ setCurrentScreen: (screenName: string) => void;
1034
+ /** Navigation ref setter — attach to your NavigationContainer */
1035
+ navigationRef: React.MutableRefObject<any>;
1036
+ }
1037
+ /**
1038
+ * Hook for tracking navigation state and enabling agent-driven navigation.
1039
+ *
1040
+ * @example
1041
+ * ```tsx
1042
+ * const { currentScreen, navigationRef } = useAppilotsNavigation();
1043
+ *
1044
+ * return (
1045
+ * <NavigationContainer ref={navigationRef}>
1046
+ * <Stack.Navigator />
1047
+ * </NavigationContainer>
1048
+ * );
1049
+ * ```
1050
+ */
1051
+ declare function useAppilotsNavigation(): UseAppilotsNavigationReturn;
1052
+
1053
+ interface UseAppilotsChatReturn {
1054
+ messages: ChatMessage[];
1055
+ isLoading: boolean;
1056
+ loadingStatusKey: 'thinking' | 'statusAnalyzing' | 'statusWaitingApp' | 'statusAdjusting';
1057
+ error: string | null;
1058
+ pendingActions: AgentAction[];
1059
+ /**
1060
+ * Open escalation, or null. While set, `sendMessage` routes to the
1061
+ * human channel — the agent session itself is never interrupted.
1062
+ */
1063
+ escalation: EscalationState | null;
1064
+ /**
1065
+ * Hand the conversation to a human operator (docs/human-escalation.md).
1066
+ * Idempotent while an escalation is open. `agent_gave_up` is used by
1067
+ * the auto-offer chip; the header button sends `user_requested`.
1068
+ */
1069
+ requestHuman: (reason?: 'user_requested' | 'agent_gave_up') => Promise<void>;
1070
+ sendMessage: (content: string) => Promise<void>;
1071
+ /**
1072
+ * Cancels the in-flight generation (OKR-008 KR4). Streamed partial
1073
+ * text is kept in the transcript; a no-op when nothing is in flight.
1074
+ * Cancellation only covers the generation phase — once actions start
1075
+ * executing on-device they run to completion (interrupting a half-done
1076
+ * form fill would leave the app in a worse state than finishing it).
1077
+ */
1078
+ cancelMessage: () => void;
1079
+ clearMessages: () => void;
1080
+ clearError: () => void;
1081
+ }
1082
+ interface UseAppilotsChatOptions {
1083
+ /** User-facing prefix for client-side failures before the relay can answer. */
1084
+ errorPrefix?: string;
1085
+ /**
1086
+ * Stream assistant replies token-by-token via SSE (default true).
1087
+ * When the streaming transport fails before any output, the hook
1088
+ * falls back to the non-streaming endpoint transparently.
1089
+ */
1090
+ streaming?: boolean;
1091
+ /** Localized escalation copy — see EscalationStrings. */
1092
+ escalationStrings?: EscalationStrings;
1093
+ }
1094
+ /**
1095
+ * Hook for managing chat state and sending messages to the Appilots agent.
1096
+ *
1097
+ * This is a thin React binding over `ChatSessionMachine` from
1098
+ * `@appilots/client-core` — the turn/continuation/recovery orchestration
1099
+ * itself is platform-agnostic and shared with the web client. Everything
1100
+ * React Native-specific (Fiber snapshotting, React Navigation settling)
1101
+ * enters through `reactNativeChatAdapter`.
1102
+ *
1103
+ * @example
1104
+ * ```tsx
1105
+ * const { messages, sendMessage, isLoading } = useAppilotsChat();
1106
+ *
1107
+ * const handleSend = () => {
1108
+ * sendMessage('Navigate to settings');
1109
+ * };
1110
+ * ```
1111
+ */
1112
+ declare function useAppilotsChat(options?: UseAppilotsChatOptions): UseAppilotsChatReturn;
1113
+
1114
+ interface UseAppilotsActionsOptions {
1115
+ /**
1116
+ * Navigation ref from useAppilotsNavigation().
1117
+ * Required for navigate actions to work.
1118
+ */
1119
+ navigationRef?: React.MutableRefObject<any>;
1120
+ /**
1121
+ * If true, actions are executed automatically without user approval.
1122
+ * Confirm actions always require approval regardless of this setting.
1123
+ * @default false
1124
+ */
1125
+ autoExecute?: boolean;
1126
+ }
1127
+ interface UseAppilotsActionsReturn {
1128
+ pendingActions: AgentAction[];
1129
+ executingActions: AgentAction[];
1130
+ completedActions: AgentAction[];
1131
+ approveAction: (actionId: string) => Promise<boolean>;
1132
+ rejectAction: (actionId: string) => Promise<void>;
1133
+ }
1134
+ /**
1135
+ * Hook for monitoring and controlling agent actions.
1136
+ *
1137
+ * A thin React binding over `ActionQueueMachine` from
1138
+ * `@appilots/client-core`: the queue, its status transitions, the
1139
+ * confirm gate (server-injected and locally synthesized) and sequential
1140
+ * auto-execution are platform-agnostic. React Native execution goes
1141
+ * through the ActionExecutor via `createReactNativeActionRunner`.
1142
+ *
1143
+ * @example
1144
+ * ```tsx
1145
+ * const { navigationRef } = useAppilotsNavigation();
1146
+ * const { pendingActions, approveAction, rejectAction } = useAppilotsActions({
1147
+ * navigationRef,
1148
+ * autoExecute: false,
1149
+ * });
1150
+ * ```
1151
+ */
1152
+ declare function useAppilotsActions(options?: UseAppilotsActionsOptions): UseAppilotsActionsReturn;
1153
+
1154
+ /**
1155
+ * ComponentRegistry — Central registry mapping component IDs to their
1156
+ * refs, callbacks, and metadata so the ActionExecutor can find and
1157
+ * interact with live UI elements.
1158
+ *
1159
+ * Screens register their interactive components via hooks
1160
+ * (useAppilotsField, useAppilotsTarget, useAppilotsToggle).
1161
+ * When the AI agent returns an action (e.g. form_fill with fieldId "plate"),
1162
+ * the executor looks up "plate" here and calls the associated setter.
1163
+ */
1164
+ type ComponentKind = 'field' | 'target' | 'toggle' | 'slider';
1165
+ interface FieldEntry {
1166
+ kind: 'field';
1167
+ /** Current value of the field */
1168
+ getValue: () => string;
1169
+ /** Set the field value programmatically */
1170
+ setValue: (value: string) => void;
1171
+ /** Optional: focus the input */
1172
+ focus?: () => void;
1173
+ /** Field type hint for the executor */
1174
+ fieldType?: 'text' | 'select' | 'toggle' | 'date' | 'number' | 'custom';
1175
+ /** Human-readable label */
1176
+ label?: string;
1177
+ /** Screen where this field is registered */
1178
+ screen?: string;
1179
+ }
1180
+ interface TargetEntry {
1181
+ kind: 'target';
1182
+ /** Execute the primary action (press) */
1183
+ press: () => void;
1184
+ /** Optional: long press */
1185
+ longPress?: () => void;
1186
+ /** Optional: scroll to this element */
1187
+ scrollTo?: () => void;
1188
+ /** Human-readable label */
1189
+ label?: string;
1190
+ /** Screen where this target is registered */
1191
+ screen?: string;
1192
+ }
1193
+ interface ToggleEntry {
1194
+ kind: 'toggle';
1195
+ /** Current value */
1196
+ getValue: () => boolean;
1197
+ /** Set the toggle value */
1198
+ setValue: (value: boolean) => void;
1199
+ /** Human-readable label */
1200
+ label?: string;
1201
+ /** Screen where this toggle is registered */
1202
+ screen?: string;
1203
+ }
1204
+ interface SliderEntry {
1205
+ kind: 'slider';
1206
+ /** Current numeric value */
1207
+ getValue: () => number;
1208
+ /**
1209
+ * Set the slider value. The executor clamps to [min, max] and snaps
1210
+ * to `step` BEFORE calling this, so implementations can trust the
1211
+ * value — but re-validating is harmless.
1212
+ */
1213
+ setValue: (value: number) => void;
1214
+ /** Lower bound (inclusive) */
1215
+ min: number;
1216
+ /** Upper bound (inclusive) */
1217
+ max: number;
1218
+ /** Step to snap to (omitted = continuous) */
1219
+ step?: number;
1220
+ /** Human-readable label */
1221
+ label?: string;
1222
+ /** Screen where this slider is registered */
1223
+ screen?: string;
1224
+ }
1225
+ type ComponentEntry = FieldEntry | TargetEntry | ToggleEntry | SliderEntry;
1226
+ type Listener = (id: string, entry: ComponentEntry | null) => void;
1227
+ /**
1228
+ * Public type for a registry instance. Both the singleton and any
1229
+ * instance returned by `createComponentRegistry()` satisfy this.
1230
+ *
1231
+ * The class itself stays internal — devs construct via the factory
1232
+ * to keep the surface minimal and future-proof.
1233
+ */
1234
+ type ComponentRegistry = ComponentRegistryImpl;
1235
+ declare class ComponentRegistryImpl {
1236
+ private components;
1237
+ private listeners;
1238
+ /**
1239
+ * Register a component. If an entry with the same ID already exists,
1240
+ * it is replaced (this handles re-renders / hot-reload).
1241
+ */
1242
+ register(id: string, entry: ComponentEntry): void;
1243
+ /**
1244
+ * Unregister a component (typically on unmount).
1245
+ */
1246
+ unregister(id: string): void;
1247
+ /**
1248
+ * Look up a component by its ID.
1249
+ */
1250
+ get(id: string): ComponentEntry | undefined;
1251
+ /**
1252
+ * Get a typed entry or undefined.
1253
+ */
1254
+ getField(id: string): FieldEntry | undefined;
1255
+ getTarget(id: string): TargetEntry | undefined;
1256
+ getToggle(id: string): ToggleEntry | undefined;
1257
+ getSlider(id: string): SliderEntry | undefined;
1258
+ /**
1259
+ * Get all components on a given screen.
1260
+ */
1261
+ getByScreen(screen: string): Map<string, ComponentEntry>;
1262
+ /**
1263
+ * Get all components of a given kind.
1264
+ */
1265
+ getByKind(kind: ComponentKind): Map<string, ComponentEntry>;
1266
+ /**
1267
+ * List all registered component IDs with their kind and screen.
1268
+ * Useful for debugging and for the AI to know what's available.
1269
+ */
1270
+ snapshot(): Array<{
1271
+ id: string;
1272
+ kind: ComponentKind;
1273
+ screen?: string;
1274
+ label?: string;
1275
+ }>;
1276
+ /**
1277
+ * Subscribe to registry changes.
1278
+ * Returns an unsubscribe function.
1279
+ */
1280
+ subscribe(listener: Listener): () => void;
1281
+ /**
1282
+ * Clear all entries (useful for testing or full reset).
1283
+ */
1284
+ clear(): void;
1285
+ /** Number of registered components */
1286
+ get size(): number;
1287
+ private notify;
1288
+ }
1289
+ /**
1290
+ * Singleton registry instance shared across the entire SDK by default.
1291
+ *
1292
+ * Apps with a single Appilots session (the overwhelmingly common case)
1293
+ * never need anything else — hooks, handlers, and auto-tracking all
1294
+ * read from this singleton.
1295
+ *
1296
+ * For multi-tenant or micro-front-end setups where two Appilots
1297
+ * sessions might coexist in the same JS process, use
1298
+ * `createComponentRegistry()` to obtain a fresh instance and pass it
1299
+ * via `<AppilotsRegistryProvider value={...}>`. Hooks resolve via
1300
+ * context first, falling back to this singleton.
1301
+ *
1302
+ * The singleton stays in place to keep the existing public API stable
1303
+ * — pré-mortem 2.8 is "future risk", not "current bug".
1304
+ */
1305
+ declare const componentRegistry: ComponentRegistry;
1306
+ /**
1307
+ * Create a fresh, isolated ComponentRegistry instance. Pair with
1308
+ * `<AppilotsRegistryProvider value={...}>` to scope auto-tracking and
1309
+ * hooks to that registry instead of the global singleton.
1310
+ *
1311
+ * @example
1312
+ * ```tsx
1313
+ * const tenantRegistry = createComponentRegistry();
1314
+ * <AppilotsRegistryProvider value={tenantRegistry}>
1315
+ * <TenantApp />
1316
+ * </AppilotsRegistryProvider>
1317
+ * ```
1318
+ */
1319
+ declare function createComponentRegistry(): ComponentRegistry;
1320
+
1321
+ /**
1322
+ * useAppilotsField — Register a text input (or similar field) with the
1323
+ * ComponentRegistry so the AI agent can fill it via form_fill actions.
1324
+ *
1325
+ * Usage:
1326
+ * ```tsx
1327
+ * const [plate, setPlate] = useState('');
1328
+ * const plateRef = useRef<TextInput>(null);
1329
+ *
1330
+ * useAppilotsField('plate', {
1331
+ * value: plate,
1332
+ * onChangeText: setPlate,
1333
+ * ref: plateRef, // optional — enables focus()
1334
+ * fieldType: 'text', // optional — hint for executor
1335
+ * label: 'License Plate', // optional — human-readable name
1336
+ * screen: 'VehicleForm', // optional — scoped to screen
1337
+ * });
1338
+ *
1339
+ * return <TextInput ref={plateRef} value={plate} onChangeText={setPlate} />;
1340
+ * ```
1341
+ */
1342
+
1343
+ interface UseAppilotsFieldOptions {
1344
+ /** Current value of the field */
1345
+ value: string;
1346
+ /** Callback to update the value (same signature as TextInput.onChangeText) */
1347
+ onChangeText: (text: string) => void;
1348
+ /** Optional ref to the TextInput for focus support */
1349
+ ref?: React.RefObject<any>;
1350
+ /** Field type hint */
1351
+ fieldType?: FieldEntry['fieldType'];
1352
+ /** Human-readable label */
1353
+ label?: string;
1354
+ /** Screen name this field belongs to */
1355
+ screen?: string;
1356
+ }
1357
+ /**
1358
+ * Register a field with the Appilots ComponentRegistry.
1359
+ * Automatically unregisters on unmount.
1360
+ *
1361
+ * @param id - Unique identifier for this field (e.g. "plate", "customerName")
1362
+ * @param options - Field configuration
1363
+ */
1364
+ declare function useAppilotsField(id: string, options: UseAppilotsFieldOptions): void;
1365
+
1366
+ /**
1367
+ * useAppilotsTarget — Register a pressable UI element (button, card, link)
1368
+ * with the ComponentRegistry so the AI agent can interact with it.
1369
+ *
1370
+ * Usage:
1371
+ * ```tsx
1372
+ * const handleSubmit = () => { ... };
1373
+ *
1374
+ * useAppilotsTarget('submitVehicle', {
1375
+ * onPress: handleSubmit,
1376
+ * label: 'Submit Vehicle',
1377
+ * screen: 'VehicleForm',
1378
+ * });
1379
+ *
1380
+ * return <Button title="Submit" onPress={handleSubmit} />;
1381
+ * ```
1382
+ */
1383
+ interface UseAppilotsTargetOptions {
1384
+ /** Primary press handler */
1385
+ onPress: () => void;
1386
+ /** Optional long-press handler */
1387
+ onLongPress?: () => void;
1388
+ /** Optional scroll-to handler (scroll this element into view) */
1389
+ onScrollTo?: () => void;
1390
+ /** Human-readable label */
1391
+ label?: string;
1392
+ /** Screen name this target belongs to */
1393
+ screen?: string;
1394
+ }
1395
+ /**
1396
+ * Register a pressable target with the Appilots ComponentRegistry.
1397
+ * Automatically unregisters on unmount.
1398
+ *
1399
+ * @param id - Unique identifier (e.g. "submitVehicle", "openSettings")
1400
+ * @param options - Target configuration
1401
+ */
1402
+ declare function useAppilotsTarget(id: string, options: UseAppilotsTargetOptions): void;
1403
+
1404
+ /**
1405
+ * useAppilotsToggle — Register a toggle/switch with the ComponentRegistry
1406
+ * so the AI agent can flip it via ui_interaction actions.
1407
+ *
1408
+ * Usage:
1409
+ * ```tsx
1410
+ * const [pushEnabled, setPushEnabled] = useState(false);
1411
+ *
1412
+ * useAppilotsToggle('pushNotifications', {
1413
+ * value: pushEnabled,
1414
+ * onValueChange: setPushEnabled,
1415
+ * label: 'Push Notifications',
1416
+ * screen: 'Settings',
1417
+ * });
1418
+ *
1419
+ * return <Switch value={pushEnabled} onValueChange={setPushEnabled} />;
1420
+ * ```
1421
+ */
1422
+ interface UseAppilotsToggleOptions {
1423
+ /** Current toggle value */
1424
+ value: boolean;
1425
+ /** Callback when value changes */
1426
+ onValueChange: (value: boolean) => void;
1427
+ /** Human-readable label */
1428
+ label?: string;
1429
+ /** Screen name this toggle belongs to */
1430
+ screen?: string;
1431
+ }
1432
+ /**
1433
+ * Register a toggle with the Appilots ComponentRegistry.
1434
+ * Automatically unregisters on unmount.
1435
+ *
1436
+ * @param id - Unique identifier (e.g. "pushNotifications", "darkMode")
1437
+ * @param options - Toggle configuration
1438
+ */
1439
+ declare function useAppilotsToggle(id: string, options: UseAppilotsToggleOptions): void;
1440
+
1441
+ /**
1442
+ * useAppilotsSlider — Register a slider / adjustable numeric control with
1443
+ * the ComponentRegistry so the AI agent can set it via
1444
+ * `ui_interaction action="set_value"` actions.
1445
+ *
1446
+ * Registration is what makes a slider agent-operable end to end:
1447
+ * captureSnapshot() reads this entry to advertise the slider (with
1448
+ * min/max/step) in the observation, and the executor dispatches
1449
+ * set_value through the same entry — clamping to [min, max] and
1450
+ * snapping to `step` before calling onValueChange.
1451
+ *
1452
+ * Usage:
1453
+ * ```tsx
1454
+ * const [mileage, setMileage] = useState(0);
1455
+ *
1456
+ * useAppilotsSlider('quilometragem', {
1457
+ * value: mileage,
1458
+ * onValueChange: setMileage,
1459
+ * min: 0,
1460
+ * max: 300000,
1461
+ * step: 500,
1462
+ * label: 'Quilometragem',
1463
+ * screen: 'VehicleCreate',
1464
+ * });
1465
+ *
1466
+ * return <MySlider value={mileage} onChange={setMileage} min={0} max={300000} />;
1467
+ * ```
1468
+ */
1469
+ interface UseAppilotsSliderOptions {
1470
+ /** Current slider value */
1471
+ value: number;
1472
+ /** Callback when value changes */
1473
+ onValueChange: (value: number) => void;
1474
+ /** Lower bound (inclusive) — advertised in the observation and enforced by the executor */
1475
+ min: number;
1476
+ /** Upper bound (inclusive) — advertised in the observation and enforced by the executor */
1477
+ max: number;
1478
+ /** Step the executor snaps to (omit for a continuous slider) */
1479
+ step?: number;
1480
+ /** Human-readable label */
1481
+ label?: string;
1482
+ /** Screen name this slider belongs to */
1483
+ screen?: string;
1484
+ }
1485
+ /**
1486
+ * Register a slider with the Appilots ComponentRegistry.
1487
+ * Automatically unregisters on unmount.
1488
+ *
1489
+ * @param id - Unique identifier (e.g. "quilometragem", "volume")
1490
+ * @param options - Slider configuration
1491
+ */
1492
+ declare function useAppilotsSlider(id: string, options: UseAppilotsSliderOptions): void;
1493
+
1494
+ interface SuggestedPrompt {
1495
+ /** Display label shown on the chip and inserted into the input on tap. */
1496
+ text: string;
1497
+ /** Where this prompt came from. Useful for analytics or theming. */
1498
+ source: 'dev-defined' | 'screen-popular' | 'global-popular';
1499
+ }
1500
+ interface UseSuggestedPromptsOptions {
1501
+ /**
1502
+ * Whether the chat is currently open. Hook only fetches while open, so
1503
+ * suggestions don't waste a roundtrip when the chat is minimised.
1504
+ */
1505
+ enabled: boolean;
1506
+ /** Max chips to return. Default 4. */
1507
+ limit?: number;
1508
+ }
1509
+ interface UseSuggestedPromptsReturn {
1510
+ prompts: SuggestedPrompt[];
1511
+ isLoading: boolean;
1512
+ /** Re-runs the fetch — call after navigation so chips refresh. */
1513
+ refetch: () => void;
1514
+ }
1515
+ /**
1516
+ * Returns ranked suggested prompts to render as chips in the chat
1517
+ * empty-state. Three sources are merged in priority order:
1518
+ *
1519
+ * 1. **Dev-defined** — from `registerScreen({ suggestedPrompts })` in the
1520
+ * current app, read synchronously from the local screen registry.
1521
+ * First-class signal, always wins.
1522
+ *
1523
+ * 2. **Screen-popular** — historical user prompts sent FROM this screen,
1524
+ * mined server-side from agentMessages history.
1525
+ *
1526
+ * 3. **Global-popular** — historical user prompts across the project.
1527
+ * Fallback for screens with no history yet.
1528
+ *
1529
+ * The hook re-fetches whenever the active screen changes so chips always
1530
+ * match where the user is right now. Server response is cached 1h, so
1531
+ * fetches are cheap.
1532
+ *
1533
+ * @example
1534
+ * ```tsx
1535
+ * const { prompts } = useSuggestedPrompts({ enabled: chatVisible });
1536
+ * return prompts.map((p) => (
1537
+ * <Chip key={p.text} onPress={() => setInput(p.text)}>{p.text}</Chip>
1538
+ * ));
1539
+ * ```
1540
+ */
1541
+ declare function useSuggestedPrompts(options: UseSuggestedPromptsOptions): UseSuggestedPromptsReturn;
1542
+
1543
+ export { createComponentRegistry as $, type AppilotsThemeTokens as A, type BreadcrumbItem as B, type ComponentRegistry as C, SDK_VERSION as D, type EscalationState as E, type FieldEntry as F, type SliderEntry as G, type SuggestedPrompt as H, type InteractionElementSnapshot as I, type ToggleEntry as J, type ToggleSnapshot as K, type ListItemSnapshot as L, type MessageRole as M, type NavigationPayload as N, type UseAppilotsFieldOptions as O, type PartialThemeTokens as P, type UseAppilotsSliderOptions as Q, type RemotePersonalization as R, type ScreenSnapshot as S, type TargetEntry as T, type UIInteractionPayload as U, type UseAppilotsTargetOptions as V, type UseAppilotsToggleOptions as W, type UseSuggestedPromptsOptions as X, type UseSuggestedPromptsReturn as Y, clearAppilotsDebugTraces as Z, componentRegistry as _, type AppilotsLocale as a, defaultDarkTheme as a0, defaultLightTheme as a1, describeAction as a2, getAppilotsDebugTraces as a3, humanizeError as a4, mergeThemeTokens as a5, recordAppilotsDebugTrace as a6, subscribeAppilotsDebugTraces as a7, useAppilots as a8, useAppilotsActions as a9, useAppilotsChat as aa, useAppilotsContext as ab, useAppilotsField as ac, useAppilotsNavigation as ad, useAppilotsSlider as ae, useAppilotsTarget as af, useAppilotsToggle as ag, useSuggestedPrompts as ah, type AgentAction as b, type AgentPermissions as c, type AppilotsEvent as d, type AgentActionType as e, type AgentMessage as f, AppilotsClient as g, type AppilotsClientOptions as h, type AppilotsConfig as i, type AppilotsEventHandler as j, type AppilotsEventType as k, AppilotsProvider as l, type AppilotsProviderProps as m, type AppilotsTraceEntry as n, type AppilotsUser as o, type BreadcrumbState as p, type ButtonSnapshot as q, type ChatMessage as r, type ChoiceGroupSnapshot as s, type ChoiceOptionSnapshot as t, type ComponentEntry as u, type ComponentKind as v, type FormFillPayload as w, type InputSnapshot as x, type InteractionElementListContext as y, type ListSnapshot as z };