@mobileai/react-native 0.9.17 → 0.9.19
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/LICENSE +28 -20
- package/MobileAIFloatingOverlay.podspec +25 -0
- package/android/build.gradle +61 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/mobileai/overlay/FloatingOverlayView.kt +151 -0
- package/android/src/main/java/com/mobileai/overlay/MobileAIOverlayPackage.kt +23 -0
- package/android/src/newarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +45 -0
- package/android/src/oldarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +29 -0
- package/ios/MobileAIFloatingOverlayComponentView.mm +73 -0
- package/lib/module/components/AIAgent.js +902 -136
- package/lib/module/components/AIConsentDialog.js +439 -0
- package/lib/module/components/AgentChatBar.js +828 -134
- package/lib/module/components/AgentOverlay.js +2 -1
- package/lib/module/components/DiscoveryTooltip.js +21 -9
- package/lib/module/components/FloatingOverlayWrapper.js +108 -0
- package/lib/module/components/Icons.js +123 -0
- package/lib/module/config/endpoints.js +12 -2
- package/lib/module/core/AgentRuntime.js +373 -27
- package/lib/module/core/FiberAdapter.js +56 -0
- package/lib/module/core/FiberTreeWalker.js +186 -80
- package/lib/module/core/IdleDetector.js +19 -0
- package/lib/module/core/NativeAlertInterceptor.js +191 -0
- package/lib/module/core/systemPrompt.js +203 -45
- package/lib/module/index.js +3 -0
- package/lib/module/providers/GeminiProvider.js +72 -56
- package/lib/module/providers/ProviderFactory.js +6 -2
- package/lib/module/services/AudioInputService.js +3 -12
- package/lib/module/services/AudioOutputService.js +1 -13
- package/lib/module/services/ConversationService.js +166 -0
- package/lib/module/services/MobileAIKnowledgeRetriever.js +41 -0
- package/lib/module/services/VoiceService.js +29 -8
- package/lib/module/services/telemetry/MobileAI.js +44 -0
- package/lib/module/services/telemetry/TelemetryService.js +13 -1
- package/lib/module/services/telemetry/TouchAutoCapture.js +44 -18
- package/lib/module/specs/FloatingOverlayNativeComponent.ts +19 -0
- package/lib/module/support/CSATSurvey.js +95 -12
- package/lib/module/support/EscalationSocket.js +70 -1
- package/lib/module/support/ReportedIssueEventSource.js +148 -0
- package/lib/module/support/escalateTool.js +4 -2
- package/lib/module/support/index.js +1 -0
- package/lib/module/support/reportIssueTool.js +127 -0
- package/lib/module/support/supportPrompt.js +77 -9
- package/lib/module/tools/guideTool.js +2 -1
- package/lib/module/tools/longPressTool.js +4 -3
- package/lib/module/tools/pickerTool.js +6 -4
- package/lib/module/tools/tapTool.js +12 -3
- package/lib/module/tools/typeTool.js +19 -10
- package/lib/module/utils/logger.js +175 -6
- package/lib/typescript/react-native.config.d.ts +11 -0
- package/lib/typescript/src/components/AIAgent.d.ts +28 -2
- package/lib/typescript/src/components/AIConsentDialog.d.ts +153 -0
- package/lib/typescript/src/components/AgentChatBar.d.ts +15 -2
- package/lib/typescript/src/components/DiscoveryTooltip.d.ts +3 -1
- package/lib/typescript/src/components/FloatingOverlayWrapper.d.ts +51 -0
- package/lib/typescript/src/components/Icons.d.ts +8 -0
- package/lib/typescript/src/config/endpoints.d.ts +5 -3
- package/lib/typescript/src/core/AgentRuntime.d.ts +4 -0
- package/lib/typescript/src/core/FiberAdapter.d.ts +25 -0
- package/lib/typescript/src/core/FiberTreeWalker.d.ts +2 -0
- package/lib/typescript/src/core/IdleDetector.d.ts +11 -0
- package/lib/typescript/src/core/NativeAlertInterceptor.d.ts +55 -0
- package/lib/typescript/src/core/types.d.ts +106 -1
- package/lib/typescript/src/index.d.ts +9 -4
- package/lib/typescript/src/providers/GeminiProvider.d.ts +6 -5
- package/lib/typescript/src/services/ConversationService.d.ts +55 -0
- package/lib/typescript/src/services/MobileAIKnowledgeRetriever.d.ts +9 -0
- package/lib/typescript/src/services/telemetry/MobileAI.d.ts +7 -0
- package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +1 -1
- package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts +9 -6
- package/lib/typescript/src/services/telemetry/types.d.ts +3 -1
- package/lib/typescript/src/specs/FloatingOverlayNativeComponent.d.ts +17 -0
- package/lib/typescript/src/support/EscalationSocket.d.ts +17 -0
- package/lib/typescript/src/support/ReportedIssueEventSource.d.ts +24 -0
- package/lib/typescript/src/support/escalateTool.d.ts +5 -0
- package/lib/typescript/src/support/index.d.ts +2 -1
- package/lib/typescript/src/support/reportIssueTool.d.ts +20 -0
- package/lib/typescript/src/support/types.d.ts +56 -1
- package/lib/typescript/src/utils/logger.d.ts +15 -0
- package/package.json +20 -9
- package/react-native.config.js +12 -0
- package/lib/module/__cli_tmp__.js.map +0 -1
- package/lib/module/components/AIAgent.js.map +0 -1
- package/lib/module/components/AIZone.js.map +0 -1
- package/lib/module/components/AgentChatBar.js.map +0 -1
- package/lib/module/components/AgentErrorBoundary.js.map +0 -1
- package/lib/module/components/AgentOverlay.js.map +0 -1
- package/lib/module/components/DiscoveryTooltip.js.map +0 -1
- package/lib/module/components/HighlightOverlay.js.map +0 -1
- package/lib/module/components/Icons.js.map +0 -1
- package/lib/module/components/ProactiveHint.js.map +0 -1
- package/lib/module/components/cards/InfoCard.js.map +0 -1
- package/lib/module/components/cards/ReviewSummary.js.map +0 -1
- package/lib/module/config/endpoints.js.map +0 -1
- package/lib/module/core/ActionRegistry.js.map +0 -1
- package/lib/module/core/AgentRuntime.js.map +0 -1
- package/lib/module/core/FiberTreeWalker.js.map +0 -1
- package/lib/module/core/IdleDetector.js.map +0 -1
- package/lib/module/core/MCPBridge.js.map +0 -1
- package/lib/module/core/ScreenDehydrator.js.map +0 -1
- package/lib/module/core/ZoneRegistry.js.map +0 -1
- package/lib/module/core/systemPrompt.js.map +0 -1
- package/lib/module/core/types.js.map +0 -1
- package/lib/module/hooks/useAction.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/plugin/withAppIntents.js.map +0 -1
- package/lib/module/providers/GeminiProvider.js.map +0 -1
- package/lib/module/providers/OpenAIProvider.js.map +0 -1
- package/lib/module/providers/ProviderFactory.js.map +0 -1
- package/lib/module/services/AudioInputService.js.map +0 -1
- package/lib/module/services/AudioOutputService.js.map +0 -1
- package/lib/module/services/KnowledgeBaseService.js.map +0 -1
- package/lib/module/services/VoiceService.js.map +0 -1
- package/lib/module/services/flags/FlagService.js.map +0 -1
- package/lib/module/services/telemetry/MobileAI.js.map +0 -1
- package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
- package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
- package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
- package/lib/module/services/telemetry/device.js.map +0 -1
- package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
- package/lib/module/services/telemetry/index.js.map +0 -1
- package/lib/module/services/telemetry/types.js.map +0 -1
- package/lib/module/support/CSATSurvey.js.map +0 -1
- package/lib/module/support/EscalationEventSource.js.map +0 -1
- package/lib/module/support/EscalationSocket.js.map +0 -1
- package/lib/module/support/SupportChatModal.js.map +0 -1
- package/lib/module/support/SupportGreeting.js.map +0 -1
- package/lib/module/support/TicketStore.js.map +0 -1
- package/lib/module/support/escalateTool.js.map +0 -1
- package/lib/module/support/index.js.map +0 -1
- package/lib/module/support/supportPrompt.js.map +0 -1
- package/lib/module/support/types.js.map +0 -1
- package/lib/module/tools/datePickerTool.js.map +0 -1
- package/lib/module/tools/guideTool.js.map +0 -1
- package/lib/module/tools/index.js.map +0 -1
- package/lib/module/tools/keyboardTool.js.map +0 -1
- package/lib/module/tools/longPressTool.js.map +0 -1
- package/lib/module/tools/pickerTool.js.map +0 -1
- package/lib/module/tools/restoreTool.js.map +0 -1
- package/lib/module/tools/scrollTool.js.map +0 -1
- package/lib/module/tools/simplifyTool.js.map +0 -1
- package/lib/module/tools/sliderTool.js.map +0 -1
- package/lib/module/tools/tapTool.js.map +0 -1
- package/lib/module/tools/typeTool.js.map +0 -1
- package/lib/module/tools/types.js.map +0 -1
- package/lib/module/types/jsx.d.js.map +0 -1
- package/lib/module/utils/audioUtils.js.map +0 -1
- package/lib/module/utils/logger.js.map +0 -1
- package/lib/typescript/babel.config.d.ts.map +0 -1
- package/lib/typescript/bin/generate-map.d.cts.map +0 -1
- package/lib/typescript/eslint.config.d.mts.map +0 -1
- package/lib/typescript/generate-map.d.ts.map +0 -1
- package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
- package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
- package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
- package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
- package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
- package/lib/typescript/src/components/Icons.d.ts.map +0 -1
- package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
- package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
- package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
- package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
- package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
- package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
- package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
- package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
- package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
- package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
- package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
- package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
- package/lib/typescript/src/core/types.d.ts.map +0 -1
- package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
- package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
- package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
- package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
- package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
- package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
- package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
- package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
- package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
- package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
- package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
- package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
- package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
- package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
- package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
- package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
- package/lib/typescript/src/support/index.d.ts.map +0 -1
- package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
- package/lib/typescript/src/support/types.d.ts.map +0 -1
- package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/index.d.ts.map +0 -1
- package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/types.d.ts.map +0 -1
- package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
- package/lib/typescript/src/utils/logger.d.ts.map +0 -1
- package/src/__cli_tmp__.tsx +0 -9
- package/src/cli/analyzers/chain-analyzer.ts +0 -183
- package/src/cli/extractors/ai-extractor.ts +0 -6
- package/src/cli/extractors/ast-extractor.ts +0 -551
- package/src/cli/generate-intents.ts +0 -140
- package/src/cli/generate-map.ts +0 -121
- package/src/cli/generate-swift.ts +0 -116
- package/src/cli/scanners/expo-scanner.ts +0 -203
- package/src/cli/scanners/rn-scanner.ts +0 -445
- package/src/components/AIAgent.tsx +0 -1716
- package/src/components/AIZone.tsx +0 -147
- package/src/components/AgentChatBar.tsx +0 -1143
- package/src/components/AgentErrorBoundary.tsx +0 -78
- package/src/components/AgentOverlay.tsx +0 -73
- package/src/components/DiscoveryTooltip.tsx +0 -148
- package/src/components/HighlightOverlay.tsx +0 -136
- package/src/components/Icons.tsx +0 -253
- package/src/components/ProactiveHint.tsx +0 -145
- package/src/components/cards/InfoCard.tsx +0 -58
- package/src/components/cards/ReviewSummary.tsx +0 -76
- package/src/config/endpoints.ts +0 -22
- package/src/core/ActionRegistry.ts +0 -105
- package/src/core/AgentRuntime.ts +0 -1471
- package/src/core/FiberTreeWalker.ts +0 -930
- package/src/core/IdleDetector.ts +0 -72
- package/src/core/MCPBridge.ts +0 -163
- package/src/core/ScreenDehydrator.ts +0 -53
- package/src/core/ZoneRegistry.ts +0 -44
- package/src/core/systemPrompt.ts +0 -431
- package/src/core/types.ts +0 -521
- package/src/hooks/useAction.ts +0 -182
- package/src/index.ts +0 -83
- package/src/plugin/withAppIntents.ts +0 -98
- package/src/providers/GeminiProvider.ts +0 -357
- package/src/providers/OpenAIProvider.ts +0 -379
- package/src/providers/ProviderFactory.ts +0 -36
- package/src/services/AudioInputService.ts +0 -226
- package/src/services/AudioOutputService.ts +0 -236
- package/src/services/KnowledgeBaseService.ts +0 -156
- package/src/services/VoiceService.ts +0 -451
- package/src/services/flags/FlagService.ts +0 -137
- package/src/services/telemetry/MobileAI.ts +0 -66
- package/src/services/telemetry/PiiScrubber.ts +0 -17
- package/src/services/telemetry/TelemetryService.ts +0 -323
- package/src/services/telemetry/TouchAutoCapture.ts +0 -165
- package/src/services/telemetry/device.ts +0 -93
- package/src/services/telemetry/deviceMetadata.ts +0 -13
- package/src/services/telemetry/index.ts +0 -13
- package/src/services/telemetry/types.ts +0 -75
- package/src/support/CSATSurvey.tsx +0 -304
- package/src/support/EscalationEventSource.ts +0 -190
- package/src/support/EscalationSocket.ts +0 -152
- package/src/support/SupportChatModal.tsx +0 -563
- package/src/support/SupportGreeting.tsx +0 -161
- package/src/support/TicketStore.ts +0 -100
- package/src/support/escalateTool.ts +0 -174
- package/src/support/index.ts +0 -29
- package/src/support/supportPrompt.ts +0 -55
- package/src/support/types.ts +0 -155
- package/src/tools/datePickerTool.ts +0 -60
- package/src/tools/guideTool.ts +0 -76
- package/src/tools/index.ts +0 -20
- package/src/tools/keyboardTool.ts +0 -30
- package/src/tools/longPressTool.ts +0 -61
- package/src/tools/pickerTool.ts +0 -115
- package/src/tools/restoreTool.ts +0 -33
- package/src/tools/scrollTool.ts +0 -156
- package/src/tools/simplifyTool.ts +0 -33
- package/src/tools/sliderTool.ts +0 -65
- package/src/tools/tapTool.ts +0 -93
- package/src/tools/typeTool.ts +0 -113
- package/src/tools/types.ts +0 -58
- package/src/types/jsx.d.ts +0 -20
- package/src/utils/audioUtils.ts +0 -54
- package/src/utils/logger.ts +0 -38
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TicketStore — persists the active support ticket across app restarts.
|
|
3
|
-
*
|
|
4
|
-
* Uses @react-native-async-storage/async-storage as an optional peer dependency.
|
|
5
|
-
* If AsyncStorage is not installed, all methods silently no-op and the feature
|
|
6
|
-
* degrades gracefully (tickets are still shown while the app is open, just not
|
|
7
|
-
* restored after a restart).
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* await TicketStore.save(ticketId, analyticsKey); // on escalation start
|
|
11
|
-
* const pending = await TicketStore.get(); // on AIAgent mount
|
|
12
|
-
* await TicketStore.clear(); // on modal close / ticket closed
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const STORAGE_KEY = '@mobileai_pending_ticket';
|
|
16
|
-
|
|
17
|
-
interface PendingTicket {
|
|
18
|
-
ticketId: string;
|
|
19
|
-
analyticsKey: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Try to load AsyncStorage at runtime. Optional peer dep — not bundled. */
|
|
23
|
-
function getAsyncStorage(): any | null {
|
|
24
|
-
try {
|
|
25
|
-
// Suppress the RN red box that AsyncStorage triggers when its native module
|
|
26
|
-
// isn't linked ("NativeModule: AsyncStorage is null").
|
|
27
|
-
const origError = console.error;
|
|
28
|
-
console.error = (...args: unknown[]) => {
|
|
29
|
-
const msg = args[0];
|
|
30
|
-
if (typeof msg === 'string' && msg.includes('AsyncStorage')) return;
|
|
31
|
-
origError.apply(console, args);
|
|
32
|
-
};
|
|
33
|
-
try {
|
|
34
|
-
const mod = require('@react-native-async-storage/async-storage');
|
|
35
|
-
const candidate = mod?.default ?? mod?.AsyncStorage ?? null;
|
|
36
|
-
if (candidate && typeof candidate.getItem === 'function') {
|
|
37
|
-
return candidate;
|
|
38
|
-
}
|
|
39
|
-
return null;
|
|
40
|
-
} finally {
|
|
41
|
-
console.error = origError;
|
|
42
|
-
}
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const TicketStore = {
|
|
49
|
-
/**
|
|
50
|
-
* Persist the active ticket so it survives an app restart.
|
|
51
|
-
*/
|
|
52
|
-
async save(ticketId: string, analyticsKey: string): Promise<void> {
|
|
53
|
-
const AS = getAsyncStorage();
|
|
54
|
-
if (!AS) {
|
|
55
|
-
console.warn(
|
|
56
|
-
'[TicketStore] @react-native-async-storage/async-storage is not installed — ' +
|
|
57
|
-
'ticket will not persist across app restarts. ' +
|
|
58
|
-
'Run: npx expo install @react-native-async-storage/async-storage'
|
|
59
|
-
);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
await AS.setItem(STORAGE_KEY, JSON.stringify({ ticketId, analyticsKey }));
|
|
64
|
-
console.log('[TicketStore] Ticket saved:', ticketId);
|
|
65
|
-
} catch (err) {
|
|
66
|
-
console.error('[TicketStore] Failed to save ticket:', err);
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Retrieve the persisted pending ticket, if any.
|
|
72
|
-
* Returns null if nothing is stored or AsyncStorage is unavailable.
|
|
73
|
-
*/
|
|
74
|
-
async get(): Promise<PendingTicket | null> {
|
|
75
|
-
const AS = getAsyncStorage();
|
|
76
|
-
if (!AS) return null;
|
|
77
|
-
try {
|
|
78
|
-
const raw = await AS.getItem(STORAGE_KEY);
|
|
79
|
-
if (!raw) return null;
|
|
80
|
-
return JSON.parse(raw) as PendingTicket;
|
|
81
|
-
} catch (err) {
|
|
82
|
-
console.error('[TicketStore] Failed to read ticket:', err);
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Remove the stored ticket (ticket closed or user dismissed modal).
|
|
89
|
-
*/
|
|
90
|
-
async clear(): Promise<void> {
|
|
91
|
-
const AS = getAsyncStorage();
|
|
92
|
-
if (!AS) return;
|
|
93
|
-
try {
|
|
94
|
-
await AS.removeItem(STORAGE_KEY);
|
|
95
|
-
console.log('[TicketStore] Pending ticket cleared');
|
|
96
|
-
} catch (err) {
|
|
97
|
-
console.error('[TicketStore] Failed to clear ticket:', err);
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
};
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Escalate tool — hands off the conversation to a human agent.
|
|
3
|
-
*
|
|
4
|
-
* Providers:
|
|
5
|
-
* - 'mobileai' (default when analyticsKey present):
|
|
6
|
-
* POSTs to MobileAI /api/v1/escalations → gets ticketId + wsUrl
|
|
7
|
-
* Opens WebSocket via EscalationSocket → agent reply pushed in real time
|
|
8
|
-
* - 'custom': fires the consumer's onEscalate callback (backward compatible)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { ToolDefinition } from '../core/types';
|
|
12
|
-
import type { EscalationConfig, EscalationContext } from './types';
|
|
13
|
-
import { EscalationSocket } from './EscalationSocket';
|
|
14
|
-
|
|
15
|
-
import { ENDPOINTS } from '../config/endpoints';
|
|
16
|
-
import { getDeviceId } from '../services/telemetry/device';
|
|
17
|
-
import { getDeviceMetadata } from '../services/telemetry/deviceMetadata';
|
|
18
|
-
import { logger } from '../utils/logger';
|
|
19
|
-
|
|
20
|
-
const MOBILEAI_HOST = ENDPOINTS.escalation;
|
|
21
|
-
|
|
22
|
-
export interface EscalationToolDeps {
|
|
23
|
-
config: EscalationConfig;
|
|
24
|
-
analyticsKey?: string;
|
|
25
|
-
getContext: () => Omit<EscalationContext, 'conversationSummary'>;
|
|
26
|
-
getHistory: () => Array<{ role: string; content: string }>;
|
|
27
|
-
getScreenFlow?: () => string[];
|
|
28
|
-
onHumanReply?: (reply: string, ticketId?: string) => void;
|
|
29
|
-
onEscalationStarted?: (ticketId: string, socket: EscalationSocket) => void;
|
|
30
|
-
onTypingChange?: (isTyping: boolean) => void;
|
|
31
|
-
onTicketClosed?: (ticketId?: string) => void;
|
|
32
|
-
userContext?: {
|
|
33
|
-
userId?: string;
|
|
34
|
-
name?: string;
|
|
35
|
-
email?: string;
|
|
36
|
-
phone?: string;
|
|
37
|
-
plan?: string;
|
|
38
|
-
custom?: Record<string, string | number | boolean>;
|
|
39
|
-
};
|
|
40
|
-
pushToken?: string;
|
|
41
|
-
pushTokenType?: 'fcm' | 'expo' | 'apns';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function createEscalateTool(deps: EscalationToolDeps): ToolDefinition;
|
|
45
|
-
/** @deprecated Use createEscalateTool({ config, analyticsKey, getContext, getHistory }) */
|
|
46
|
-
export function createEscalateTool(
|
|
47
|
-
config: EscalationConfig,
|
|
48
|
-
getContext: () => Omit<EscalationContext, 'conversationSummary'>
|
|
49
|
-
): ToolDefinition;
|
|
50
|
-
export function createEscalateTool(
|
|
51
|
-
depsOrConfig: EscalationToolDeps | EscalationConfig,
|
|
52
|
-
legacyGetContext?: () => Omit<EscalationContext, 'conversationSummary'>
|
|
53
|
-
): ToolDefinition {
|
|
54
|
-
// Normalise both call signatures
|
|
55
|
-
let deps: EscalationToolDeps;
|
|
56
|
-
if (legacyGetContext) {
|
|
57
|
-
deps = {
|
|
58
|
-
config: depsOrConfig as EscalationConfig,
|
|
59
|
-
getContext: legacyGetContext,
|
|
60
|
-
getHistory: () => [],
|
|
61
|
-
};
|
|
62
|
-
} else {
|
|
63
|
-
deps = depsOrConfig as EscalationToolDeps;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const { config, analyticsKey, getContext, getHistory, onHumanReply, onEscalationStarted, onTypingChange, onTicketClosed, userContext, pushToken, pushTokenType, getScreenFlow } = deps;
|
|
67
|
-
|
|
68
|
-
// Determine effective provider
|
|
69
|
-
const provider = config.provider ?? (analyticsKey ? 'mobileai' : 'custom');
|
|
70
|
-
|
|
71
|
-
// Socket instance kept here — one per tool instance
|
|
72
|
-
let socket: EscalationSocket | null = null;
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
name: 'escalate_to_human',
|
|
76
|
-
description:
|
|
77
|
-
'Hand off the conversation to a human support agent. ' +
|
|
78
|
-
'Use this when: (1) the user explicitly asks for a human, ' +
|
|
79
|
-
'(2) you cannot resolve the issue after multiple attempts, or ' +
|
|
80
|
-
'(3) the topic requires human judgment (billing disputes, account issues).',
|
|
81
|
-
parameters: {
|
|
82
|
-
reason: {
|
|
83
|
-
type: 'string',
|
|
84
|
-
description: 'Brief summary of why escalation is needed and what has been tried',
|
|
85
|
-
required: true,
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
execute: async (args: Record<string, unknown>) => {
|
|
89
|
-
const reason = String(args.reason ?? 'User requested human support');
|
|
90
|
-
const context = getContext();
|
|
91
|
-
|
|
92
|
-
if (provider === 'mobileai') {
|
|
93
|
-
if (!analyticsKey) {
|
|
94
|
-
logger.warn('Escalation', 'provider=mobileai but no analyticsKey — falling back to custom');
|
|
95
|
-
} else {
|
|
96
|
-
try {
|
|
97
|
-
const history = getHistory().slice(-20); // last 20 messages for context
|
|
98
|
-
logger.info('Escalation', '★★★ Creating ticket — reason:', reason, '| deviceId:', getDeviceId());
|
|
99
|
-
const res = await fetch(`${MOBILEAI_HOST}/api/v1/escalations`, {
|
|
100
|
-
method: 'POST',
|
|
101
|
-
headers: { 'Content-Type': 'application/json' },
|
|
102
|
-
body: JSON.stringify({
|
|
103
|
-
analyticsKey,
|
|
104
|
-
reason,
|
|
105
|
-
screen: context.currentScreen,
|
|
106
|
-
history,
|
|
107
|
-
stepsBeforeEscalation: context.stepsBeforeEscalation,
|
|
108
|
-
userContext: {
|
|
109
|
-
...userContext,
|
|
110
|
-
device: getDeviceMetadata(),
|
|
111
|
-
},
|
|
112
|
-
screenFlow: getScreenFlow?.() ?? [],
|
|
113
|
-
pushToken,
|
|
114
|
-
pushTokenType,
|
|
115
|
-
deviceId: getDeviceId(),
|
|
116
|
-
}),
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
if (res.ok) {
|
|
120
|
-
const { ticketId, wsUrl } = await res.json();
|
|
121
|
-
logger.info('Escalation', '★★★ Ticket created:', ticketId, '| wsUrl:', wsUrl);
|
|
122
|
-
|
|
123
|
-
// Connect WebSocket for real-time reply
|
|
124
|
-
socket?.disconnect();
|
|
125
|
-
socket = new EscalationSocket({
|
|
126
|
-
onReply: (reply, replyTicketId) => {
|
|
127
|
-
logger.info('Escalation', '★★★ Human reply for ticket', ticketId, ':', reply.substring(0, 80));
|
|
128
|
-
onHumanReply?.(reply, replyTicketId || ticketId);
|
|
129
|
-
},
|
|
130
|
-
onTypingChange: (v) => {
|
|
131
|
-
logger.info('Escalation', '★★★ Agent typing:', v);
|
|
132
|
-
onTypingChange?.(v);
|
|
133
|
-
},
|
|
134
|
-
onTicketClosed: (closedTicketId) => {
|
|
135
|
-
logger.info('Escalation', '★★★ Ticket closed:', ticketId);
|
|
136
|
-
onTicketClosed?.(closedTicketId || ticketId);
|
|
137
|
-
},
|
|
138
|
-
onError: (err) => {
|
|
139
|
-
logger.error('Escalation', '★★★ WebSocket error:', err);
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
socket.connect(wsUrl);
|
|
143
|
-
logger.info('Escalation', '★★★ WebSocket connecting...');
|
|
144
|
-
|
|
145
|
-
// Pass the socket to UI
|
|
146
|
-
logger.info('Escalation', '★★★ Calling onEscalationStarted for ticket:', ticketId);
|
|
147
|
-
onEscalationStarted?.(ticketId, socket);
|
|
148
|
-
logger.info('Escalation', '★★★ onEscalationStarted DONE');
|
|
149
|
-
} else {
|
|
150
|
-
logger.error('Escalation', 'Failed to create ticket:', res.status);
|
|
151
|
-
}
|
|
152
|
-
} catch (err) {
|
|
153
|
-
logger.error('Escalation', 'Network error:', (err as Error).message);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const message = config.escalationMessage ?? 'Connecting you to a human agent...';
|
|
157
|
-
return `ESCALATED: ${message}`;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// 'custom' provider — fire callback
|
|
162
|
-
const escalationContext: EscalationContext = {
|
|
163
|
-
conversationSummary: reason,
|
|
164
|
-
currentScreen: context.currentScreen,
|
|
165
|
-
originalQuery: context.originalQuery,
|
|
166
|
-
stepsBeforeEscalation: context.stepsBeforeEscalation,
|
|
167
|
-
};
|
|
168
|
-
config.onEscalate?.(escalationContext);
|
|
169
|
-
|
|
170
|
-
const message = config.escalationMessage ?? 'Connecting you to a human agent...';
|
|
171
|
-
return `ESCALATED: ${message}`;
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
}
|
package/src/support/index.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Support Mode — barrel export.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// Types
|
|
6
|
-
export type {
|
|
7
|
-
SupportModeConfig,
|
|
8
|
-
QuickReply,
|
|
9
|
-
EscalationConfig,
|
|
10
|
-
EscalationContext,
|
|
11
|
-
CSATConfig,
|
|
12
|
-
CSATRating,
|
|
13
|
-
BusinessHoursConfig,
|
|
14
|
-
SupportTicket,
|
|
15
|
-
} from './types';
|
|
16
|
-
|
|
17
|
-
// Prompt injection
|
|
18
|
-
export { buildSupportPrompt } from './supportPrompt';
|
|
19
|
-
|
|
20
|
-
// Escalation tool + WebSocket manager
|
|
21
|
-
export { createEscalateTool } from './escalateTool';
|
|
22
|
-
export { EscalationSocket } from './EscalationSocket';
|
|
23
|
-
export type { SocketReplyHandler } from './EscalationSocket';
|
|
24
|
-
export { EscalationEventSource } from './EscalationEventSource';
|
|
25
|
-
|
|
26
|
-
// UI Components
|
|
27
|
-
export { SupportGreeting } from './SupportGreeting';
|
|
28
|
-
export { CSATSurvey } from './CSATSurvey';
|
|
29
|
-
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Support Mode prompt — injected into the system prompt when support mode is enabled.
|
|
3
|
-
*
|
|
4
|
-
* Uses POSITIVE framing (what TO DO) instead of negative rules (per user's prompt engineering rules).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { SupportModeConfig } from './types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Build the support mode system prompt addition.
|
|
11
|
-
* This gets appended to the main system prompt when support mode is active.
|
|
12
|
-
*/
|
|
13
|
-
export function buildSupportPrompt(config: SupportModeConfig): string {
|
|
14
|
-
const parts: string[] = [];
|
|
15
|
-
|
|
16
|
-
// Core support persona
|
|
17
|
-
parts.push(`
|
|
18
|
-
## Support Mode Active
|
|
19
|
-
|
|
20
|
-
You are a helpful customer support assistant. Your primary goal is to resolve the user's issue quickly and empathetically.
|
|
21
|
-
|
|
22
|
-
### Behavior Guidelines
|
|
23
|
-
- Greet the user warmly and acknowledge their issue
|
|
24
|
-
- Ask clarifying questions when the user's request is ambiguous
|
|
25
|
-
- Provide step-by-step guidance when helping with app features
|
|
26
|
-
- Use the app's UI tools to demonstrate solutions visually (tap, navigate, type)
|
|
27
|
-
- After resolving, confirm with the user that their issue is fixed
|
|
28
|
-
- Stay focused on the user's current issue — complete one task before moving to another
|
|
29
|
-
`);
|
|
30
|
-
|
|
31
|
-
// Custom system context from the consumer
|
|
32
|
-
if (config.systemContext) {
|
|
33
|
-
parts.push(`### App Context\n${config.systemContext}\n`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Auto-escalate topics
|
|
37
|
-
if (config.autoEscalateTopics?.length) {
|
|
38
|
-
parts.push(
|
|
39
|
-
`### Auto-Escalation Topics\n` +
|
|
40
|
-
`When the user's query matches any of these topics, use the escalate_to_human tool immediately:\n` +
|
|
41
|
-
config.autoEscalateTopics.map((t) => `- ${t}`).join('\n') + '\n'
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Business hours context
|
|
46
|
-
if (config.businessHours) {
|
|
47
|
-
parts.push(
|
|
48
|
-
`### Business Hours\n` +
|
|
49
|
-
`The support team operates in timezone: ${config.businessHours.timezone}.\n` +
|
|
50
|
-
`If outside business hours, inform the user and offer to help with what you can.\n`
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return parts.join('\n');
|
|
55
|
-
}
|
package/src/support/types.ts
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Support Mode — types and configuration.
|
|
3
|
-
*
|
|
4
|
-
* Transforms the AI agent into a customer support assistant with:
|
|
5
|
-
* - Custom greeting message
|
|
6
|
-
* - Quick reply suggestions
|
|
7
|
-
* - Human escalation capability
|
|
8
|
-
* - CSAT (Customer Satisfaction) collection after conversation
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// ─── Support Mode Config ──────────────────────────────────
|
|
12
|
-
|
|
13
|
-
export interface SupportModeConfig {
|
|
14
|
-
/** Enable support mode. Default: false */
|
|
15
|
-
enabled: boolean;
|
|
16
|
-
|
|
17
|
-
/** Greeting message shown when the chat opens */
|
|
18
|
-
greeting?: {
|
|
19
|
-
/** Main greeting text (e.g., "Hi! 👋 How can I help you today?") */
|
|
20
|
-
message: string;
|
|
21
|
-
/** Agent name shown above the greeting (e.g., "MobileAI Support") */
|
|
22
|
-
agentName?: string;
|
|
23
|
-
/** Avatar URL for the support agent */
|
|
24
|
-
avatarUrl?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/** Quick reply buttons shown below the greeting */
|
|
28
|
-
quickReplies?: QuickReply[];
|
|
29
|
-
|
|
30
|
-
/** Escalation configuration */
|
|
31
|
-
escalation?: EscalationConfig;
|
|
32
|
-
|
|
33
|
-
/** CSAT survey configuration */
|
|
34
|
-
csat?: CSATConfig;
|
|
35
|
-
|
|
36
|
-
/** Business hours (optional — shows offline message outside hours) */
|
|
37
|
-
businessHours?: BusinessHoursConfig;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Additional system prompt context for the support persona.
|
|
41
|
-
* Merged with the base system prompt.
|
|
42
|
-
* Example: "You are a friendly support agent for FeedYum food delivery app."
|
|
43
|
-
*/
|
|
44
|
-
systemContext?: string;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Topics the AI should NOT attempt to resolve — escalate immediately.
|
|
48
|
-
* Example: ['billing dispute', 'account deletion', 'legal']
|
|
49
|
-
*/
|
|
50
|
-
autoEscalateTopics?: string[];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ─── Quick Replies ────────────────────────────────────────
|
|
54
|
-
|
|
55
|
-
export interface QuickReply {
|
|
56
|
-
/** Display text on the button */
|
|
57
|
-
label: string;
|
|
58
|
-
/** Message sent when tapped (defaults to label if not set) */
|
|
59
|
-
message?: string;
|
|
60
|
-
/** Icon emoji (optional) */
|
|
61
|
-
icon?: string;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ─── Escalation ───────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
export interface EscalationConfig {
|
|
67
|
-
/**
|
|
68
|
-
* Where to route the escalation.
|
|
69
|
-
* - 'mobileai' (default when analyticsKey is set): ticket goes to MobileAI
|
|
70
|
-
* dashboard inbox via POST /api/v1/escalations + WebSocket reply delivery.
|
|
71
|
-
* - 'custom': fires the onEscalate callback — wire to Intercom, Zendesk, etc.
|
|
72
|
-
*/
|
|
73
|
-
provider?: 'mobileai' | 'custom';
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Callback when user requests human support (required when provider='custom').
|
|
77
|
-
* Use this to open a live chat widget, send email, etc.
|
|
78
|
-
*/
|
|
79
|
-
onEscalate?: (context: EscalationContext) => void;
|
|
80
|
-
|
|
81
|
-
/** Label for the escalate button. Default: "Talk to a human" */
|
|
82
|
-
buttonLabel?: string;
|
|
83
|
-
|
|
84
|
-
/** Message shown to user when escalated. Default: "Connecting you to a human agent..." */
|
|
85
|
-
escalationMessage?: string;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface EscalationContext {
|
|
89
|
-
/** Summary of the conversation so far */
|
|
90
|
-
conversationSummary: string;
|
|
91
|
-
/** Current screen the user is on */
|
|
92
|
-
currentScreen: string;
|
|
93
|
-
/** User's original question/issue */
|
|
94
|
-
originalQuery: string;
|
|
95
|
-
/** Number of AI steps taken before escalation */
|
|
96
|
-
stepsBeforeEscalation: number;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ─── CSAT (Customer Satisfaction) ─────────────────────────
|
|
100
|
-
|
|
101
|
-
export interface CSATConfig {
|
|
102
|
-
/** Enable CSAT survey after conversation. Default: true if support mode enabled */
|
|
103
|
-
enabled?: boolean;
|
|
104
|
-
|
|
105
|
-
/** Question text. Default: "How was your experience?" */
|
|
106
|
-
question?: string;
|
|
107
|
-
|
|
108
|
-
/** Rating type. Default: 'emoji' */
|
|
109
|
-
ratingType?: 'stars' | 'emoji' | 'thumbs';
|
|
110
|
-
|
|
111
|
-
/** Callback when user submits rating */
|
|
112
|
-
onSubmit: (rating: CSATRating) => void;
|
|
113
|
-
|
|
114
|
-
/** Show after N seconds of inactivity. Default: 10 */
|
|
115
|
-
showAfterIdleSeconds?: number;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface CSATRating {
|
|
119
|
-
/** Numeric score (1-5 for stars/emoji, 0-1 for thumbs) */
|
|
120
|
-
score: number;
|
|
121
|
-
/** Optional text feedback */
|
|
122
|
-
feedback?: string;
|
|
123
|
-
/** Conversation metadata */
|
|
124
|
-
metadata: {
|
|
125
|
-
conversationDuration: number;
|
|
126
|
-
stepsCount: number;
|
|
127
|
-
wasEscalated: boolean;
|
|
128
|
-
screen: string;
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ─── Business Hours ───────────────────────────────────────
|
|
133
|
-
|
|
134
|
-
export interface BusinessHoursConfig {
|
|
135
|
-
/** Timezone (IANA format, e.g., 'Africa/Cairo') */
|
|
136
|
-
timezone: string;
|
|
137
|
-
/** Schedule per day of week (0=Sunday, 6=Saturday) */
|
|
138
|
-
schedule: Record<number, { start: string; end: string } | null>;
|
|
139
|
-
/** Message shown outside business hours */
|
|
140
|
-
offlineMessage?: string;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// ─── Support Ticket ───────────────────────────────────────
|
|
144
|
-
|
|
145
|
-
export interface SupportTicket {
|
|
146
|
-
id: string;
|
|
147
|
-
reason: string;
|
|
148
|
-
screen: string;
|
|
149
|
-
status: string;
|
|
150
|
-
history: Array<{ role: string; content: string; timestamp?: string }>;
|
|
151
|
-
createdAt: string;
|
|
152
|
-
wsUrl: string;
|
|
153
|
-
/** Number of unread messages (computed by backend = history.length - readMessageCount) */
|
|
154
|
-
unreadCount?: number;
|
|
155
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Picker Tool — Set date/time picker values.
|
|
3
|
-
*
|
|
4
|
-
* Pattern from Detox: setDatePickerDate(dateString, dateFormat)
|
|
5
|
-
*
|
|
6
|
-
* In JS: calls onChange(event, date) with a Date object.
|
|
7
|
-
* The event parameter mimics the native event shape: { nativeEvent: { timestamp } }
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { walkFiberTree } from '../core/FiberTreeWalker';
|
|
11
|
-
import type { AgentTool, ToolContext } from './types';
|
|
12
|
-
|
|
13
|
-
export function createDatePickerTool(context: ToolContext): AgentTool {
|
|
14
|
-
return {
|
|
15
|
-
name: 'set_date',
|
|
16
|
-
description: 'Set the value of a date/time picker. Provide the date in ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss).',
|
|
17
|
-
parameters: {
|
|
18
|
-
index: { type: 'number', description: 'The index of the date picker element', required: true },
|
|
19
|
-
date: { type: 'string', description: 'Date in ISO 8601 format, e.g., "2025-03-25" or "2025-03-25T14:30:00"', required: true },
|
|
20
|
-
},
|
|
21
|
-
execute: async (args) => {
|
|
22
|
-
const { interactives: elements } = walkFiberTree(context.getRootRef(), context.getWalkConfig());
|
|
23
|
-
const element = elements.find(el => el.index === args.index);
|
|
24
|
-
if (!element) {
|
|
25
|
-
return `❌ Element with index ${args.index} not found.`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Parse the date string
|
|
29
|
-
const dateObj = new Date(args.date);
|
|
30
|
-
if (isNaN(dateObj.getTime())) {
|
|
31
|
-
return `❌ Invalid date format: "${args.date}". Use ISO 8601 format (e.g., "2025-03-25" or "2025-03-25T14:30:00").`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Find onChange handler (DateTimePicker's primary callback)
|
|
35
|
-
const onChange = element.props.onChange || element.props.onDateChange || element.props.onConfirm;
|
|
36
|
-
if (!onChange || typeof onChange !== 'function') {
|
|
37
|
-
return `❌ Element [${args.index}] "${element.label}" is not a date picker (no onChange/onDateChange handler).`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
// Mimic native event shape (like DateTimePicker's native event)
|
|
42
|
-
const syntheticEvent = {
|
|
43
|
-
type: 'set',
|
|
44
|
-
nativeEvent: {
|
|
45
|
-
timestamp: dateObj.getTime(),
|
|
46
|
-
utcOffset: 0,
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
onChange(syntheticEvent, dateObj);
|
|
51
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
52
|
-
|
|
53
|
-
const formattedDate = dateObj.toLocaleDateString();
|
|
54
|
-
return `✅ Set date picker [${args.index}] "${element.label}" to ${formattedDate}`;
|
|
55
|
-
} catch (error: any) {
|
|
56
|
-
return `❌ Error setting date: ${error.message}`;
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|
package/src/tools/guideTool.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { DeviceEventEmitter } from 'react-native';
|
|
2
|
-
import type { ToolDefinition } from '../core/types';
|
|
3
|
-
import type { ToolContext } from './types';
|
|
4
|
-
import { logger } from '../utils/logger';
|
|
5
|
-
|
|
6
|
-
export function createGuideTool(context: ToolContext): ToolDefinition {
|
|
7
|
-
return {
|
|
8
|
-
name: 'guide_user',
|
|
9
|
-
description: 'Highlight a specific element to draw the user\'s attention. Use when you want to show the user where to tap next. Auto-dismisses after a few seconds.',
|
|
10
|
-
parameters: {
|
|
11
|
-
index: {
|
|
12
|
-
type: 'number',
|
|
13
|
-
description: 'Fiber element index from the screen layout',
|
|
14
|
-
required: true,
|
|
15
|
-
},
|
|
16
|
-
message: {
|
|
17
|
-
type: 'string',
|
|
18
|
-
description: 'Short instruction shown near the highlighted element (e.g. "Tap here to continue")',
|
|
19
|
-
required: true,
|
|
20
|
-
},
|
|
21
|
-
autoRemoveAfterMs: {
|
|
22
|
-
type: 'number',
|
|
23
|
-
description: 'Auto-dismiss after this many milliseconds. Default: 5000',
|
|
24
|
-
required: false,
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
execute: async (args: Record<string, any>) => {
|
|
28
|
-
const lastDehydratedRoot = context.getLastDehydratedRoot?.();
|
|
29
|
-
if (!lastDehydratedRoot) {
|
|
30
|
-
return '❌ Cannot guide user: No screen layout structure available.';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const index = Number(args.index);
|
|
34
|
-
const element = lastDehydratedRoot.elements[index];
|
|
35
|
-
|
|
36
|
-
if (process.env.NODE_ENV === 'test') {
|
|
37
|
-
// Fallback for react-test-renderer which provides a dummy measure() that never fires callbacks
|
|
38
|
-
DeviceEventEmitter.emit('MOBILE_AI_HIGHLIGHT', {
|
|
39
|
-
pageX: 0,
|
|
40
|
-
pageY: 0,
|
|
41
|
-
width: 100,
|
|
42
|
-
height: 100,
|
|
43
|
-
message: args.message,
|
|
44
|
-
autoRemoveAfterMs: args.autoRemoveAfterMs || 5000,
|
|
45
|
-
});
|
|
46
|
-
return `✅ Highlighted element ${index} ("${element.label}") with message: "${args.message}"`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const stateNode = element.fiberNode?.stateNode;
|
|
50
|
-
if (!stateNode || typeof stateNode.measure !== 'function') {
|
|
51
|
-
return `❌ Element at index ${index} (${element.label}) cannot be highlighted because its layout position cannot be measured.`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return new Promise((resolve) => {
|
|
55
|
-
stateNode.measure((_x: number, _y: number, width: number, height: number, pageX: number, pageY: number) => {
|
|
56
|
-
if (width === 0 || height === 0) {
|
|
57
|
-
resolve(`❌ Element at index ${index} is not visible (0x0 size)`);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
DeviceEventEmitter.emit('MOBILE_AI_HIGHLIGHT', {
|
|
62
|
-
pageX,
|
|
63
|
-
pageY,
|
|
64
|
-
width,
|
|
65
|
-
height,
|
|
66
|
-
message: args.message,
|
|
67
|
-
autoRemoveAfterMs: args.autoRemoveAfterMs || 5000,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
logger.info('GuideTool', `Highlighted element ${index} ("${element.label}") at ${pageX},${pageY}`);
|
|
71
|
-
resolve(`✅ Highlighted element ${index} ("${element.label}") with message: "${args.message}"`);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
}
|
package/src/tools/index.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool Module Barrel Export
|
|
3
|
-
*
|
|
4
|
-
* All tool factory functions are exported from here.
|
|
5
|
-
* AgentRuntime imports this single file to register all tools.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export { createTapTool } from './tapTool';
|
|
9
|
-
export { createLongPressTool } from './longPressTool';
|
|
10
|
-
export { createTypeTool } from './typeTool';
|
|
11
|
-
export { createScrollTool } from './scrollTool';
|
|
12
|
-
export { createSliderTool } from './sliderTool';
|
|
13
|
-
export { createPickerTool } from './pickerTool';
|
|
14
|
-
export { createDatePickerTool } from './datePickerTool';
|
|
15
|
-
export { createKeyboardTool } from './keyboardTool';
|
|
16
|
-
export { createGuideTool } from './guideTool';
|
|
17
|
-
export { createSimplifyTool } from './simplifyTool';
|
|
18
|
-
export { createRestoreTool } from './restoreTool';
|
|
19
|
-
|
|
20
|
-
export type { AgentTool, ToolContext, ToolParameter } from './types';
|