@mobileai/react-native 0.9.27 → 0.9.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +24 -11
  2. package/android/build.gradle +17 -0
  3. package/android/src/main/java/com/mobileai/overlay/FloatingOverlayDialogRootViewGroup.kt +243 -0
  4. package/android/src/main/java/com/mobileai/overlay/FloatingOverlayView.kt +281 -87
  5. package/android/src/newarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +52 -17
  6. package/android/src/oldarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +49 -2
  7. package/bin/generate-map.cjs +45 -6
  8. package/ios/Podfile +63 -0
  9. package/ios/Podfile.lock +2290 -0
  10. package/ios/Podfile.properties.json +4 -0
  11. package/ios/mobileaireactnative/AppDelegate.swift +69 -0
  12. package/ios/mobileaireactnative/Images.xcassets/AppIcon.appiconset/Contents.json +13 -0
  13. package/ios/mobileaireactnative/Images.xcassets/Contents.json +6 -0
  14. package/ios/mobileaireactnative/Images.xcassets/SplashScreenLegacy.imageset/Contents.json +21 -0
  15. package/ios/mobileaireactnative/Images.xcassets/SplashScreenLegacy.imageset/SplashScreenLegacy.png +0 -0
  16. package/ios/mobileaireactnative/Info.plist +55 -0
  17. package/ios/mobileaireactnative/PrivacyInfo.xcprivacy +48 -0
  18. package/ios/mobileaireactnative/SplashScreen.storyboard +47 -0
  19. package/ios/mobileaireactnative/Supporting/Expo.plist +6 -0
  20. package/ios/mobileaireactnative/mobileaireactnative-Bridging-Header.h +3 -0
  21. package/ios/mobileaireactnative.xcodeproj/project.pbxproj +547 -0
  22. package/ios/mobileaireactnative.xcodeproj/xcshareddata/xcschemes/mobileaireactnative.xcscheme +88 -0
  23. package/ios/mobileaireactnative.xcworkspace/contents.xcworkspacedata +10 -0
  24. package/lib/module/components/AIAgent.js +405 -168
  25. package/lib/module/components/AgentChatBar.js +250 -59
  26. package/lib/module/components/FloatingOverlayWrapper.js +68 -32
  27. package/lib/module/config/endpoints.js +22 -1
  28. package/lib/module/core/AgentRuntime.js +103 -1
  29. package/lib/module/core/FiberTreeWalker.js +98 -0
  30. package/lib/module/core/OutcomeVerifier.js +149 -0
  31. package/lib/module/core/systemPrompt.js +96 -25
  32. package/lib/module/providers/GeminiProvider.js +9 -3
  33. package/lib/module/services/telemetry/TelemetryService.js +21 -2
  34. package/lib/module/services/telemetry/TouchAutoCapture.js +45 -35
  35. package/lib/module/specs/FloatingOverlayNativeComponent.ts +7 -1
  36. package/lib/module/support/supportPrompt.js +22 -7
  37. package/lib/module/support/supportStyle.js +55 -0
  38. package/lib/module/support/types.js +2 -0
  39. package/lib/module/tools/typeTool.js +20 -0
  40. package/lib/module/utils/humanizeScreenName.js +49 -0
  41. package/lib/typescript/src/components/AIAgent.d.ts +6 -2
  42. package/lib/typescript/src/components/AgentChatBar.d.ts +15 -1
  43. package/lib/typescript/src/components/FloatingOverlayWrapper.d.ts +22 -10
  44. package/lib/typescript/src/config/endpoints.d.ts +4 -0
  45. package/lib/typescript/src/core/AgentRuntime.d.ts +9 -0
  46. package/lib/typescript/src/core/FiberTreeWalker.d.ts +12 -1
  47. package/lib/typescript/src/core/OutcomeVerifier.d.ts +46 -0
  48. package/lib/typescript/src/core/systemPrompt.d.ts +3 -10
  49. package/lib/typescript/src/core/types.d.ts +35 -0
  50. package/lib/typescript/src/index.d.ts +1 -0
  51. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +7 -1
  52. package/lib/typescript/src/services/telemetry/types.d.ts +1 -1
  53. package/lib/typescript/src/specs/FloatingOverlayNativeComponent.d.ts +5 -0
  54. package/lib/typescript/src/support/index.d.ts +1 -0
  55. package/lib/typescript/src/support/supportStyle.d.ts +9 -0
  56. package/lib/typescript/src/support/types.d.ts +3 -0
  57. package/lib/typescript/src/utils/humanizeScreenName.d.ts +6 -0
  58. package/package.json +5 -2
  59. package/src/specs/FloatingOverlayNativeComponent.ts +7 -1
  60. package/ios/MobileAIFloatingOverlayComponentView.mm +0 -73
  61. package/ios/MobileAIPilotIntents.swift +0 -51
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Transforms raw navigation route names into human-readable labels.
5
+ * Designed to handle both Expo Router (file-based) and React Navigation conventions.
6
+ */
7
+ export function humanizeScreenName(route) {
8
+ if (!route) return '';
9
+ let name = route;
10
+
11
+ // 1. Strip Expo Router groups: e.g., "(tabs)/index" -> "index"
12
+ // Keep replacing in case of nested groups like "(app)/(tabs)/home"
13
+ name = name.replace(/\([^)]+\)\//g, '');
14
+
15
+ // 2. Skip internal layout and catch-all routes
16
+ if (name.includes('_layout') || name.includes('[...')) {
17
+ return '';
18
+ }
19
+
20
+ // 3. Handle nested indexes: "settings/index" -> "settings"
21
+ if (name.endsWith('/index')) {
22
+ name = name.replace(/\/index$/, '');
23
+ }
24
+
25
+ // 4. Special case root index
26
+ if (name === 'index') {
27
+ return 'Home';
28
+ }
29
+
30
+ // 5. Strip dynamic brackets: "[id]" -> "id"
31
+ name = name.replace(/\[([^\]]+)\]/g, '$1');
32
+
33
+ // Strip leading/trailing slashes just in case
34
+ name = name.replace(/^\/|\/$/g, '');
35
+
36
+ // 6. Split on kebab-case, snake_case, slash, and camelCase boundaries
37
+ // e.g., "product-details" -> "product details"
38
+ // e.g., "order_history" -> "order history"
39
+ // e.g., "UserProfile" -> "User Profile"
40
+ // e.g., "settings/profile" -> "settings profile"
41
+ name = name.replace(/[-_/]/g, ' ')
42
+ // Insert a space before all caps (but not at the start) to separate camelCase/PascalCase
43
+ .replace(/([a-z])([A-Z])/g, '$1 $2');
44
+
45
+ // 7. Title-case each word and clean extra spaces
46
+ name = name.split(/\s+/).filter(Boolean).map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
47
+ return name;
48
+ }
49
+ //# sourceMappingURL=humanizeScreenName.js.map
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import React from 'react';
11
11
  import type { AIConsentConfig } from './AIConsentDialog';
12
- import type { ExecutionResult, ToolDefinition, AgentStep, TokenUsage, KnowledgeBaseConfig, ChatBarTheme, AIProviderName, ScreenMap, ProactiveHelpConfig, InteractionMode, CustomerSuccessConfig, OnboardingConfig } from '../core/types';
12
+ import type { ExecutionResult, ToolDefinition, AgentStep, TokenUsage, KnowledgeBaseConfig, ChatBarTheme, AIProviderName, ScreenMap, ProactiveHelpConfig, InteractionMode, CustomerSuccessConfig, OnboardingConfig, VerifierConfig, SupportStyle } from '../core/types';
13
13
  interface AIAgentProps {
14
14
  /**
15
15
  * API key (for local prototyping only).
@@ -41,6 +41,10 @@ interface AIAgentProps {
41
41
  voiceProxyHeaders?: Record<string, string>;
42
42
  /** LLM model name (provider-specific) */
43
43
  model?: string;
44
+ /** Support personality preset. Default: 'warm-concise'. */
45
+ supportStyle?: SupportStyle;
46
+ /** Optional outcome verifier configuration for critical actions. */
47
+ verifier?: VerifierConfig;
44
48
  /** Navigation container ref (from useNavigationContainerRef) */
45
49
  navRef?: any;
46
50
  /** Max agent steps per request */
@@ -216,6 +220,6 @@ interface AIAgentProps {
216
220
  */
217
221
  consent?: AIConsentConfig;
218
222
  }
219
- export declare function AIAgent({ apiKey, proxyUrl, proxyHeaders, voiceProxyUrl, voiceProxyHeaders, provider: providerName, model, navRef, maxSteps, showChatBar, children, onResult, interactiveBlacklist, interactiveWhitelist, onBeforeStep, onAfterStep, onBeforeTask, onAfterTask, transformScreenContent, customTools, instructions, stepDelay, mcpServerUrl, router, pathname, enableVoice, onTokenUsage, debug, knowledgeBase, knowledgeMaxTokens, enableUIControl, accentColor, theme, screenMap, useScreenMap, maxTokenBudget, maxCostUSD, analyticsKey, analyticsProxyUrl, analyticsProxyHeaders, proactiveHelp, userContext, pushToken, pushTokenType, interactionMode, showDiscoveryTooltip: showDiscoveryTooltipProp, discoveryTooltipMessage, customerSuccess, onboarding, consent, }: AIAgentProps): import("react/jsx-runtime").JSX.Element;
223
+ export declare function AIAgent({ apiKey, proxyUrl, proxyHeaders, voiceProxyUrl, voiceProxyHeaders, provider: providerName, model, supportStyle, verifier, navRef, maxSteps, showChatBar, children, onResult, interactiveBlacklist, interactiveWhitelist, onBeforeStep, onAfterStep, onBeforeTask, onAfterTask, transformScreenContent, customTools, instructions, stepDelay, mcpServerUrl, router, pathname, enableVoice, onTokenUsage, debug, knowledgeBase, knowledgeMaxTokens, enableUIControl, accentColor, theme, screenMap, useScreenMap, maxTokenBudget, maxCostUSD, analyticsKey, analyticsProxyUrl, analyticsProxyHeaders, proactiveHelp, userContext, pushToken, pushTokenType, interactionMode, showDiscoveryTooltip: showDiscoveryTooltipProp, discoveryTooltipMessage, customerSuccess, onboarding, consent, }: AIAgentProps): import("react/jsx-runtime").JSX.Element;
220
224
  export {};
221
225
  //# sourceMappingURL=AIAgent.d.ts.map
@@ -7,6 +7,7 @@ import type { ExecutionResult, AgentMode, ChatBarTheme, AIMessage, ConversationS
7
7
  import type { SupportTicket } from '../support/types';
8
8
  interface AgentChatBarProps {
9
9
  onSend: (message: string) => void;
10
+ onCancel?: () => void;
10
11
  isThinking: boolean;
11
12
  statusText?: string;
12
13
  lastResult: ExecutionResult | null;
@@ -67,7 +68,20 @@ interface AgentChatBarProps {
67
68
  onNewConversation?: () => void;
68
69
  pendingApprovalQuestion?: string | null;
69
70
  onPendingApprovalAction?: (action: 'approve' | 'reject') => void;
71
+ renderMode?: 'default' | 'android-native-window';
72
+ onWindowMetricsChange?: (metrics: {
73
+ x: number;
74
+ y: number;
75
+ width: number;
76
+ height: number;
77
+ }) => void;
78
+ windowMetrics?: {
79
+ x: number;
80
+ y: number;
81
+ width: number;
82
+ height: number;
83
+ } | null;
70
84
  }
71
- export declare function AgentChatBar({ onSend, isThinking, statusText, lastResult, language, availableModes, mode, onModeChange, onMicToggle, onSpeakerToggle, isMicActive, isSpeakerMuted, isAISpeaking, isVoiceConnected, onStopSession, theme, tickets, selectedTicketId, onTicketSelect, autoExpandTrigger, unreadCounts, totalUnread, showDiscoveryTooltip, discoveryTooltipMessage, onTooltipDismiss, chatMessages, conversations, isLoadingHistory, onConversationSelect, onNewConversation, pendingApprovalQuestion, onPendingApprovalAction, }: AgentChatBarProps): import("react/jsx-runtime").JSX.Element;
85
+ export declare function AgentChatBar({ onSend, onCancel, isThinking, statusText, lastResult, language, availableModes, mode, onModeChange, onMicToggle, onSpeakerToggle, isMicActive, isSpeakerMuted, isAISpeaking, isVoiceConnected, onStopSession, theme, tickets, selectedTicketId, onTicketSelect, autoExpandTrigger, unreadCounts, totalUnread, showDiscoveryTooltip, discoveryTooltipMessage, onTooltipDismiss, chatMessages, conversations, isLoadingHistory, onConversationSelect, onNewConversation, pendingApprovalQuestion, onPendingApprovalAction, renderMode, onWindowMetricsChange, windowMetrics, }: AgentChatBarProps): import("react/jsx-runtime").JSX.Element;
72
86
  export {};
73
87
  //# sourceMappingURL=AgentChatBar.d.ts.map
@@ -9,13 +9,10 @@
9
9
  * Renders ABOVE all native Modals, system alerts, and navigation chrome.
10
10
  * 2. Falls back to plain View if react-native-screens is not installed.
11
11
  *
12
- * Android (both Old and New Architecture):
13
- * 1. Native `MobileAIFloatingOverlay` ViewManager (bundled in this library).
14
- * Creates a Dialog window with TYPE_APPLICATION_PANEL (z=1000),
15
- * above normal app Dialog windows (TYPE_APPLICATION, z=2).
16
- * No SYSTEM_ALERT_WINDOW permission needed — scoped to app's own window.
17
- * 2. Falls back to plain View if the app hasn't been rebuilt after install
18
- * (graceful degradation with DEV warning).
12
+ * Android:
13
+ * 1. Uses a native panel dialog window when explicit bounds are provided.
14
+ * This keeps the floating agent compact and above native modal surfaces.
15
+ * 2. Falls back to a plain View otherwise.
19
16
  *
20
17
  * Usage:
21
18
  * <FloatingOverlayWrapper fallbackStyle={styles.floatingLayer}>
@@ -28,24 +25,39 @@
28
25
  * Note: FullWindowOverlay on iOS does NOT officially accept style props in its TS definition,
29
26
  * but passing StyleSheet.absoluteFill is often necessary to prevent dimensions collapsing conditionally.
30
27
  */
28
+ import React from 'react';
31
29
  /**
32
30
  * True when a native elevated overlay is available on the current platform.
33
31
  * Used by AIConsentDialog to decide whether to render as View vs Modal.
34
32
  *
35
33
  * iOS + react-native-screens installed → true
36
- * Android + native rebuild done → true
37
34
  * Everything else (fallback) → false
38
35
  */
39
36
  export declare const isNativeOverlayActive: boolean;
40
37
  interface FloatingOverlayWrapperProps {
41
38
  children: React.ReactNode;
39
+ androidWindowMetrics?: {
40
+ x: number;
41
+ y: number;
42
+ width: number;
43
+ height: number;
44
+ } | null;
45
+ onAndroidWindowDragEnd?: (metrics: {
46
+ x: number;
47
+ y: number;
48
+ width: number;
49
+ height: number;
50
+ }) => void;
42
51
  /**
43
52
  * Style applied to the View wrapper when no native overlay is available.
44
53
  * Ignored on iOS (FullWindowOverlay creates its own UIWindow) and
45
- * Android (native module creates its own Dialog window).
54
+ * Android (native module creates its own panel dialog window).
46
55
  */
47
56
  fallbackStyle?: any;
48
57
  }
49
- export declare function FloatingOverlayWrapper({ children, fallbackStyle, }: FloatingOverlayWrapperProps): React.ReactElement;
58
+ export interface FloatingOverlayWrapperHandle {
59
+ setAndroidWindowMetrics: (metrics: NonNullable<FloatingOverlayWrapperProps['androidWindowMetrics']>) => void;
60
+ }
61
+ export declare const FloatingOverlayWrapper: React.ForwardRefExoticComponent<FloatingOverlayWrapperProps & React.RefAttributes<FloatingOverlayWrapperHandle>>;
50
62
  export {};
51
63
  //# sourceMappingURL=FloatingOverlayWrapper.d.ts.map
@@ -8,6 +8,10 @@
8
8
  * to route telemetry through your own backend without touching this file.
9
9
  */
10
10
  export declare const ENDPOINTS: {
11
+ /** Hosted MobileAI text proxy — used by default when analyticsKey is set */
12
+ readonly hostedTextProxy: `${string}/api/v1/hosted-proxy/text`;
13
+ /** Hosted MobileAI voice proxy — used by default when analyticsKey is set */
14
+ readonly hostedVoiceProxy: `${string}/ws/hosted-proxy/voice`;
11
15
  /** Telemetry event ingest — receives batched SDK events */
12
16
  readonly telemetryIngest: `${string}/api/v1/events`;
13
17
  /** Feature flag sync — fetches remote flags for this analyticsKey */
@@ -23,6 +23,10 @@ export declare class AgentRuntime {
23
23
  private uiControlOverride?;
24
24
  private lastDehydratedRoot;
25
25
  private currentTraceId;
26
+ private currentUserGoal;
27
+ private verifierProvider;
28
+ private outcomeVerifier;
29
+ private pendingCriticalVerification;
26
30
  private originalErrorHandler;
27
31
  private lastSuppressedError;
28
32
  private graceTimer;
@@ -38,6 +42,11 @@ export declare class AgentRuntime {
38
42
  private formatInteractiveForDebug;
39
43
  private debugScreenSnapshot;
40
44
  constructor(provider: AIProvider, config: AgentConfig, rootRef: any, navRef: any);
45
+ private getVerifier;
46
+ private createCurrentVerificationSnapshot;
47
+ private updateCriticalVerification;
48
+ private maybeStartCriticalVerification;
49
+ private shouldBlockSuccessCompletion;
41
50
  private registerBuiltInTools;
42
51
  /**
43
52
  * Register only knowledge-assistant tools (no UI control).
@@ -6,7 +6,7 @@
6
6
  * interactive elements by their type and props (onPress, onChangeText, etc.).
7
7
  *
8
8
  */
9
- import type { InteractiveElement } from './types';
9
+ import type { InteractiveElement, WireframeSnapshot } from './types';
10
10
  export interface WalkConfig {
11
11
  /** React refs of elements to exclude */
12
12
  interactiveBlacklist?: React.RefObject<any>[];
@@ -64,4 +64,15 @@ export interface ScrollableContainer {
64
64
  * For ScrollView: the stateNode IS the native scroll view directly.
65
65
  */
66
66
  export declare function findScrollableContainers(rootRef: any, screenName?: string): ScrollableContainer[];
67
+ /**
68
+ * Capture a privacy-safe wireframe of the current screen.
69
+ *
70
+ * Performance guarantees:
71
+ * - Capped at WIREFRAME_MAX_ELEMENTS (50) — enough for wireframe context
72
+ * - Measures in batches of WIREFRAME_BATCH_SIZE (10), yielding a frame
73
+ * between batches so the bridge stays free for user interactions
74
+ * - The caller (AIAgent) defers this via InteractionManager so it
75
+ * never competes with screen transitions or gestures
76
+ */
77
+ export declare function captureWireframe(rootRef: React.RefObject<any>, config?: WalkConfig): Promise<WireframeSnapshot | null>;
67
78
  //# sourceMappingURL=FiberTreeWalker.d.ts.map
@@ -0,0 +1,46 @@
1
+ import type { AIProvider, AgentConfig, InteractiveElement } from './types';
2
+ export type VerificationStatus = 'success' | 'error' | 'uncertain';
3
+ export type VerificationFailureKind = 'controllable' | 'uncontrollable';
4
+ export interface VerificationSnapshot {
5
+ screenName: string;
6
+ screenContent: string;
7
+ elements: InteractiveElement[];
8
+ screenshot?: string;
9
+ }
10
+ export interface VerificationAction {
11
+ toolName: string;
12
+ args: Record<string, any>;
13
+ label: string;
14
+ targetElement?: InteractiveElement;
15
+ }
16
+ export interface VerificationContext {
17
+ goal: string;
18
+ action: VerificationAction;
19
+ preAction: VerificationSnapshot;
20
+ postAction: VerificationSnapshot;
21
+ }
22
+ export interface VerificationResult {
23
+ status: VerificationStatus;
24
+ failureKind: VerificationFailureKind;
25
+ evidence: string;
26
+ source: 'deterministic' | 'llm';
27
+ }
28
+ export interface PendingVerification {
29
+ goal: string;
30
+ action: VerificationAction;
31
+ preAction: VerificationSnapshot;
32
+ followupSteps: number;
33
+ }
34
+ export declare function createVerificationSnapshot(screenName: string, screenContent: string, elements: InteractiveElement[], screenshot?: string): VerificationSnapshot;
35
+ export declare function buildVerificationAction(toolName: string, args: Record<string, any>, elements: InteractiveElement[], fallbackLabel: string): VerificationAction;
36
+ export declare function isCriticalVerificationAction(action: VerificationAction): boolean;
37
+ export declare class OutcomeVerifier {
38
+ private readonly provider;
39
+ private readonly config;
40
+ constructor(provider: AIProvider, config: AgentConfig);
41
+ isEnabled(): boolean;
42
+ getMaxFollowupSteps(): number;
43
+ isCriticalAction(action: VerificationAction): boolean;
44
+ verify(context: VerificationContext): Promise<VerificationResult>;
45
+ }
46
+ //# sourceMappingURL=OutcomeVerifier.d.ts.map
@@ -1,13 +1,6 @@
1
- /**
2
- * System prompt for the AI agent.
3
- *
4
- * Shared fragments are extracted as constants at the top so that all
5
- * three prompt builders (text agent, voice agent, knowledge-only) stay
6
- * in sync — one change propagates everywhere. The prompt uses XML-style
7
- * tags to give the LLM clear, structured instructions.
8
- */
9
- export declare function buildSystemPrompt(language: string, hasKnowledge?: boolean, isCopilot?: boolean): string;
10
- export declare function buildVoiceSystemPrompt(language: string, userInstructions?: string, hasKnowledge?: boolean): string;
1
+ import type { SupportStyle } from './types';
2
+ export declare function buildSystemPrompt(language: string, hasKnowledge?: boolean, isCopilot?: boolean, supportStyle?: SupportStyle): string;
3
+ export declare function buildVoiceSystemPrompt(language: string, userInstructions?: string, hasKnowledge?: boolean, supportStyle?: SupportStyle): string;
11
4
  /**
12
5
  * Build a knowledge-only system prompt (no UI control tools).
13
6
  *
@@ -11,6 +11,16 @@ export type AgentMode = 'text' | 'voice' | 'human';
11
11
  */
12
12
  export type InteractionMode = 'copilot' | 'autopilot';
13
13
  export type AIProviderName = 'gemini' | 'openai';
14
+ export type SupportStyle = 'warm-concise' | 'wow-service' | 'neutral-professional';
15
+ export interface VerifierConfig {
16
+ enabled?: boolean;
17
+ mode?: 'critical-actions';
18
+ provider?: AIProviderName;
19
+ model?: string;
20
+ proxyUrl?: string;
21
+ proxyHeaders?: Record<string, string>;
22
+ maxFollowupSteps?: number;
23
+ }
14
24
  export type ElementType = 'pressable' | 'text-input' | 'switch' | 'radio' | 'scrollable' | 'slider' | 'picker' | 'date-picker';
15
25
  export interface InteractiveElement {
16
26
  /** Unique index assigned during tree walk */
@@ -51,6 +61,21 @@ export interface InteractiveElement {
51
61
  alertButtonIndex: number;
52
62
  };
53
63
  }
64
+ export interface WireframeComponent {
65
+ type: ElementType;
66
+ label: string;
67
+ x: number;
68
+ y: number;
69
+ width: number;
70
+ height: number;
71
+ }
72
+ export interface WireframeSnapshot {
73
+ screen: string;
74
+ components: WireframeComponent[];
75
+ deviceWidth: number;
76
+ deviceHeight: number;
77
+ capturedAt: string;
78
+ }
54
79
  export interface DehydratedScreen {
55
80
  /** Current screen name (from navigation state) */
56
81
  screenName: string;
@@ -123,6 +148,16 @@ export interface AgentConfig {
123
148
  */
124
149
  voiceProxyHeaders?: Record<string, string>;
125
150
  model?: string;
151
+ /**
152
+ * Support personality preset used when the agent is handling support-style requests.
153
+ * Default: 'warm-concise'
154
+ */
155
+ supportStyle?: SupportStyle;
156
+ /**
157
+ * Optional outcome verifier settings for critical app-changing actions.
158
+ * Defaults to enabled critical-action verification using the main provider.
159
+ */
160
+ verifier?: VerifierConfig;
126
161
  /** Maximum steps per task */
127
162
  maxSteps?: number;
128
163
  /**
@@ -28,4 +28,5 @@ export type { TelemetryConfig, TelemetryEvent } from './services/telemetry';
28
28
  export { SupportGreeting, CSATSurvey, buildSupportPrompt, createEscalateTool, EscalationSocket, } from './support';
29
29
  export { createReportIssueTool } from './support';
30
30
  export type { SupportModeConfig, QuickReply, EscalationConfig, EscalationContext, CSATConfig, CSATRating, BusinessHoursConfig, SupportTicket, ReportedIssue, ReportedIssueCustomerStatus, ReportedIssueStatusUpdate, } from './support';
31
+ export type { SupportStyle } from './support';
31
32
  //# sourceMappingURL=index.d.ts.map
@@ -18,6 +18,7 @@ export declare class TelemetryService {
18
18
  private flushTimer;
19
19
  private isFlushing;
20
20
  private appStateSubscription;
21
+ private wireframesSent;
21
22
  get screen(): string;
22
23
  getScreenFlow(): string[];
23
24
  /**
@@ -37,7 +38,12 @@ export declare class TelemetryService {
37
38
  /** Track an event (auto or custom) */
38
39
  track(type: string, data?: Record<string, unknown>): void;
39
40
  /** Update current screen (called by AIAgent on navigation) */
40
- setScreen(screenName: string): void;
41
+ setScreen(rawScreenName: string): void;
42
+ /**
43
+ * Track a wireframe snapshot.
44
+ * Deduped per session (only one wireframe per screen over a session).
45
+ */
46
+ trackWireframe(snapshot: import('../../core/types').WireframeSnapshot): void;
41
47
  /** Send queued events to the cloud API */
42
48
  flush(): Promise<void>;
43
49
  /** Save queued events to AsyncStorage for crash/restart recovery */
@@ -6,7 +6,7 @@
6
6
  * 2. Consumer-tracked: via MobileAI.track() API
7
7
  */
8
8
  /** Auto-captured event types */
9
- export type AutoEventType = 'screen_view' | 'user_action' | 'scroll_depth' | 'idle_detected' | 'session_start' | 'session_end' | 'agent_request' | 'agent_step' | 'agent_trace' | 'agent_complete' | 'escalation' | 'knowledge_query' | 'knowledge_miss' | 'csat_response' | 'ces_response' | 'agent_first_response' | 'human_first_response' | 'fcr_achieved' | 'engagement_signal' | 'health_signal' | 'onboarding_step';
9
+ export type AutoEventType = 'screen_view' | 'user_action' | 'user_interaction' | 'scroll_depth' | 'idle_detected' | 'session_start' | 'session_end' | 'agent_request' | 'agent_step' | 'agent_trace' | 'agent_complete' | 'escalation' | 'knowledge_query' | 'knowledge_miss' | 'csat_response' | 'ces_response' | 'agent_first_response' | 'human_first_response' | 'fcr_achieved' | 'engagement_signal' | 'health_signal' | 'onboarding_step' | 'business_escalation' | 'dead_click' | 'dead_click_detected' | 'rage_click' | 'rage_click_detected' | 'error_screen' | 'repeated_navigation' | 'checkout_started' | 'purchase_complete' | 'purchase_completed' | 'wireframe_snapshot';
10
10
  /** All event types (auto + custom) */
11
11
  export type EventType = AutoEventType | string;
12
12
  export interface TelemetryEvent {
@@ -10,7 +10,12 @@
10
10
  * Naming convention: file must end in NativeComponent.ts (Codegen convention).
11
11
  */
12
12
  import type { ViewProps } from 'react-native';
13
+ import type { Int32 } from 'react-native/Libraries/Types/CodegenTypes';
13
14
  export interface NativeProps extends ViewProps {
15
+ windowX?: Int32;
16
+ windowY?: Int32;
17
+ windowWidth?: Int32;
18
+ windowHeight?: Int32;
14
19
  }
15
20
  declare const _default: import("react-native/Libraries/Utilities/codegenNativeComponent").NativeComponentType<NativeProps>;
16
21
  export default _default;
@@ -2,6 +2,7 @@
2
2
  * Support Mode — barrel export.
3
3
  */
4
4
  export type { SupportModeConfig, QuickReply, EscalationConfig, EscalationContext, CSATConfig, CSATRating, BusinessHoursConfig, SupportTicket, ReportedIssue, ReportedIssueCustomerStatus, ReportedIssueStatusUpdate, } from './types';
5
+ export type { SupportStyle } from './supportStyle';
5
6
  export { buildSupportPrompt } from './supportPrompt';
6
7
  export { createEscalateTool } from './escalateTool';
7
8
  export { createReportIssueTool } from './reportIssueTool';
@@ -0,0 +1,9 @@
1
+ export type SupportStyle = 'warm-concise' | 'wow-service' | 'neutral-professional';
2
+ interface SupportStylePreset {
3
+ tone: string;
4
+ prompt: string;
5
+ }
6
+ export declare function resolveSupportStyle(style?: SupportStyle): SupportStylePreset;
7
+ export declare function buildSupportStylePrompt(style?: SupportStyle): string;
8
+ export {};
9
+ //# sourceMappingURL=supportStyle.d.ts.map
@@ -7,6 +7,7 @@
7
7
  * - Human escalation capability
8
8
  * - CSAT (Customer Satisfaction) collection after conversation
9
9
  */
10
+ import type { SupportStyle } from './supportStyle';
10
11
  export interface SupportModeConfig {
11
12
  /** Enable support mode. Default: false */
12
13
  enabled: boolean;
@@ -42,6 +43,8 @@ export interface SupportModeConfig {
42
43
  * Options for the AI's persona and tone.
43
44
  */
44
45
  persona?: {
46
+ /** Preset support personality. Default: 'warm-concise'. */
47
+ preset?: SupportStyle;
45
48
  /** The agent's name to use in conversation. */
46
49
  agentName?: string;
47
50
  /** The tone of the AI (e.g., 'professional', 'casual', 'empathetic'). Default: 'empathetic' */
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Transforms raw navigation route names into human-readable labels.
3
+ * Designed to handle both Expo Router (file-based) and React Navigation conventions.
4
+ */
5
+ export declare function humanizeScreenName(route: string | null | undefined): string;
6
+ //# sourceMappingURL=humanizeScreenName.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobileai/react-native",
3
- "version": "0.9.27",
3
+ "version": "0.9.28",
4
4
  "description": "Build autonomous AI agents for React Native and Expo apps. Provides AI-native UI traversal, tool calling, and structured reasoning.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -96,7 +96,10 @@
96
96
  "dependencies": {
97
97
  "@babel/parser": "^7.29.2",
98
98
  "@babel/traverse": "^7.29.0",
99
- "@babel/types": "^7.29.0"
99
+ "@babel/types": "^7.29.0",
100
+ "expo": "~55.0.8",
101
+ "react": "19.2.0",
102
+ "react-native": "0.83.2"
100
103
  },
101
104
  "devDependencies": {
102
105
  "@eslint/compat": "^1.3.2",
@@ -11,9 +11,15 @@
11
11
  */
12
12
 
13
13
  import type { ViewProps } from 'react-native';
14
+ import type { Int32 } from 'react-native/Libraries/Types/CodegenTypes';
14
15
  import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
15
16
 
16
- export interface NativeProps extends ViewProps {}
17
+ export interface NativeProps extends ViewProps {
18
+ windowX?: Int32;
19
+ windowY?: Int32;
20
+ windowWidth?: Int32;
21
+ windowHeight?: Int32;
22
+ }
17
23
 
18
24
  // Codegen reads this export to generate the native component interfaces.
19
25
  export default codegenNativeComponent<NativeProps>('MobileAIFloatingOverlay');
@@ -1,73 +0,0 @@
1
- #import <React/RCTViewComponentView.h>
2
- #import <UIKit/UIKit.h>
3
-
4
- #import <react/renderer/components/RNMobileAIOverlaySpec/ComponentDescriptors.h>
5
- #import <react/renderer/components/RNMobileAIOverlaySpec/EventEmitters.h>
6
- #import <react/renderer/components/RNMobileAIOverlaySpec/Props.h>
7
- #import <react/renderer/components/RNMobileAIOverlaySpec/RCTComponentViewHelpers.h>
8
-
9
- #import "RCTFabricComponentsPlugins.h"
10
-
11
- NS_ASSUME_NONNULL_BEGIN
12
- @interface MobileAIFloatingOverlayComponentView : RCTViewComponentView
13
- @end
14
- NS_ASSUME_NONNULL_END
15
-
16
- using namespace facebook::react;
17
-
18
- @interface MobileAIFloatingOverlayComponentView () <RCTMobileAIFloatingOverlayViewProtocol>
19
- @end
20
-
21
- @implementation MobileAIFloatingOverlayComponentView {
22
- UIView * _view;
23
- }
24
-
25
- + (ComponentDescriptorProvider)componentDescriptorProvider
26
- {
27
- return concreteComponentDescriptorProvider<MobileAIFloatingOverlayComponentDescriptor>();
28
- }
29
-
30
- - (instancetype)initWithFrame:(CGRect)frame
31
- {
32
- if (self = [super initWithFrame:frame]) {
33
- static const auto defaultProps = std::make_shared<const MobileAIFloatingOverlayProps>();
34
- _props = defaultProps;
35
-
36
- _view = [[UIView alloc] init];
37
-
38
- self.contentView = _view;
39
- }
40
-
41
- return self;
42
- }
43
-
44
- - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
45
- {
46
- const auto &oldViewProps = *std::static_pointer_cast<MobileAIFloatingOverlayProps const>(_props);
47
- const auto &newViewProps = *std::static_pointer_cast<MobileAIFloatingOverlayProps const>(props);
48
-
49
- [super updateProps:props oldProps:oldProps];
50
- }
51
-
52
- @end
53
-
54
- Class<RCTComponentViewProtocol> MobileAIFloatingOverlayCls(void)
55
- {
56
- return MobileAIFloatingOverlayComponentView.class;
57
- }
58
-
59
- // ─── Linker Fix: Force inclusion of the library ────────────────
60
-
61
- #import <React/RCTViewManager.h>
62
-
63
- @interface MobileAIFloatingOverlayManager : RCTViewManager
64
- @end
65
-
66
- @implementation MobileAIFloatingOverlayManager
67
- RCT_EXPORT_MODULE(MobileAIFloatingOverlay)
68
-
69
- - (UIView *)view
70
- {
71
- return [[UIView alloc] init];
72
- }
73
- @end
@@ -1,51 +0,0 @@
1
- import AppIntents
2
- import UIKit
3
-
4
- // Auto-generated by react-native-ai-agent
5
- // Do not edit manually.
6
-
7
- @available(iOS 16.0, *)
8
- struct CheckoutCartIntent: AppIntent {
9
- static var title: LocalizedStringResource = "checkout_cart"
10
- static var description = IntentDescription("Process checkout")
11
- static var openAppWhenRun: Bool = true
12
-
13
- @Parameter(title: "Total amount")
14
- var amount: Double?
15
-
16
- @Parameter(title: "Currency code")
17
- var currency: String?
18
-
19
- @Parameter(title: "Express checkout")
20
- var isExpress: Bool?
21
-
22
- @MainActor
23
- func perform() async throws -> some IntentResult {
24
- var components = URLComponents()
25
- components.scheme = "feedyum"
26
- components.host = "ai-action"
27
- components.path = "/checkout_cart"
28
- var queryItems: [URLQueryItem] = []
29
- if let val = amount {
30
- queryItems.append(URLQueryItem(name: "amount", value: String(describing: val)))
31
- }
32
- if let val = currency {
33
- queryItems.append(URLQueryItem(name: "currency", value: String(describing: val)))
34
- }
35
- if let val = isExpress {
36
- queryItems.append(URLQueryItem(name: "isExpress", value: String(describing: val)))
37
- }
38
- components.queryItems = queryItems
39
- if let url = components.url {
40
- await UIApplication.shared.open(url)
41
- }
42
- return .result()
43
- }
44
- }
45
-
46
- @available(iOS 16.0, *)
47
- struct MobileAIAppShortcuts: AppShortcutsProvider {
48
- static var appShortcuts: [AppShortcut] {
49
- AppShortcut(intent: CheckoutCartIntent(), phrases: ["\\(.applicationName) checkout cart"])
50
- }
51
- }