@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.
- package/README.md +24 -11
- package/android/build.gradle +17 -0
- package/android/src/main/java/com/mobileai/overlay/FloatingOverlayDialogRootViewGroup.kt +243 -0
- package/android/src/main/java/com/mobileai/overlay/FloatingOverlayView.kt +281 -87
- package/android/src/newarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +52 -17
- package/android/src/oldarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +49 -2
- package/bin/generate-map.cjs +45 -6
- package/ios/Podfile +63 -0
- package/ios/Podfile.lock +2290 -0
- package/ios/Podfile.properties.json +4 -0
- package/ios/mobileaireactnative/AppDelegate.swift +69 -0
- package/ios/mobileaireactnative/Images.xcassets/AppIcon.appiconset/Contents.json +13 -0
- package/ios/mobileaireactnative/Images.xcassets/Contents.json +6 -0
- package/ios/mobileaireactnative/Images.xcassets/SplashScreenLegacy.imageset/Contents.json +21 -0
- package/ios/mobileaireactnative/Images.xcassets/SplashScreenLegacy.imageset/SplashScreenLegacy.png +0 -0
- package/ios/mobileaireactnative/Info.plist +55 -0
- package/ios/mobileaireactnative/PrivacyInfo.xcprivacy +48 -0
- package/ios/mobileaireactnative/SplashScreen.storyboard +47 -0
- package/ios/mobileaireactnative/Supporting/Expo.plist +6 -0
- package/ios/mobileaireactnative/mobileaireactnative-Bridging-Header.h +3 -0
- package/ios/mobileaireactnative.xcodeproj/project.pbxproj +547 -0
- package/ios/mobileaireactnative.xcodeproj/xcshareddata/xcschemes/mobileaireactnative.xcscheme +88 -0
- package/ios/mobileaireactnative.xcworkspace/contents.xcworkspacedata +10 -0
- package/lib/module/components/AIAgent.js +405 -168
- package/lib/module/components/AgentChatBar.js +250 -59
- package/lib/module/components/FloatingOverlayWrapper.js +68 -32
- package/lib/module/config/endpoints.js +22 -1
- package/lib/module/core/AgentRuntime.js +103 -1
- package/lib/module/core/FiberTreeWalker.js +98 -0
- package/lib/module/core/OutcomeVerifier.js +149 -0
- package/lib/module/core/systemPrompt.js +96 -25
- package/lib/module/providers/GeminiProvider.js +9 -3
- package/lib/module/services/telemetry/TelemetryService.js +21 -2
- package/lib/module/services/telemetry/TouchAutoCapture.js +45 -35
- package/lib/module/specs/FloatingOverlayNativeComponent.ts +7 -1
- package/lib/module/support/supportPrompt.js +22 -7
- package/lib/module/support/supportStyle.js +55 -0
- package/lib/module/support/types.js +2 -0
- package/lib/module/tools/typeTool.js +20 -0
- package/lib/module/utils/humanizeScreenName.js +49 -0
- package/lib/typescript/src/components/AIAgent.d.ts +6 -2
- package/lib/typescript/src/components/AgentChatBar.d.ts +15 -1
- package/lib/typescript/src/components/FloatingOverlayWrapper.d.ts +22 -10
- package/lib/typescript/src/config/endpoints.d.ts +4 -0
- package/lib/typescript/src/core/AgentRuntime.d.ts +9 -0
- package/lib/typescript/src/core/FiberTreeWalker.d.ts +12 -1
- package/lib/typescript/src/core/OutcomeVerifier.d.ts +46 -0
- package/lib/typescript/src/core/systemPrompt.d.ts +3 -10
- package/lib/typescript/src/core/types.d.ts +35 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +7 -1
- package/lib/typescript/src/services/telemetry/types.d.ts +1 -1
- package/lib/typescript/src/specs/FloatingOverlayNativeComponent.d.ts +5 -0
- package/lib/typescript/src/support/index.d.ts +1 -0
- package/lib/typescript/src/support/supportStyle.d.ts +9 -0
- package/lib/typescript/src/support/types.d.ts +3 -0
- package/lib/typescript/src/utils/humanizeScreenName.d.ts +6 -0
- package/package.json +5 -2
- package/src/specs/FloatingOverlayNativeComponent.ts +7 -1
- package/ios/MobileAIFloatingOverlayComponentView.mm +0 -73
- 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
|
|
13
|
-
* 1.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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
|
|
54
|
+
* Android (native module creates its own panel dialog window).
|
|
46
55
|
*/
|
|
47
56
|
fallbackStyle?: any;
|
|
48
57
|
}
|
|
49
|
-
export
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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
|
-
}
|