@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.
Files changed (292) hide show
  1. package/LICENSE +28 -20
  2. package/MobileAIFloatingOverlay.podspec +25 -0
  3. package/android/build.gradle +61 -0
  4. package/android/src/main/AndroidManifest.xml +3 -0
  5. package/android/src/main/java/com/mobileai/overlay/FloatingOverlayView.kt +151 -0
  6. package/android/src/main/java/com/mobileai/overlay/MobileAIOverlayPackage.kt +23 -0
  7. package/android/src/newarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +45 -0
  8. package/android/src/oldarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +29 -0
  9. package/ios/MobileAIFloatingOverlayComponentView.mm +73 -0
  10. package/lib/module/components/AIAgent.js +902 -136
  11. package/lib/module/components/AIConsentDialog.js +439 -0
  12. package/lib/module/components/AgentChatBar.js +828 -134
  13. package/lib/module/components/AgentOverlay.js +2 -1
  14. package/lib/module/components/DiscoveryTooltip.js +21 -9
  15. package/lib/module/components/FloatingOverlayWrapper.js +108 -0
  16. package/lib/module/components/Icons.js +123 -0
  17. package/lib/module/config/endpoints.js +12 -2
  18. package/lib/module/core/AgentRuntime.js +373 -27
  19. package/lib/module/core/FiberAdapter.js +56 -0
  20. package/lib/module/core/FiberTreeWalker.js +186 -80
  21. package/lib/module/core/IdleDetector.js +19 -0
  22. package/lib/module/core/NativeAlertInterceptor.js +191 -0
  23. package/lib/module/core/systemPrompt.js +203 -45
  24. package/lib/module/index.js +3 -0
  25. package/lib/module/providers/GeminiProvider.js +72 -56
  26. package/lib/module/providers/ProviderFactory.js +6 -2
  27. package/lib/module/services/AudioInputService.js +3 -12
  28. package/lib/module/services/AudioOutputService.js +1 -13
  29. package/lib/module/services/ConversationService.js +166 -0
  30. package/lib/module/services/MobileAIKnowledgeRetriever.js +41 -0
  31. package/lib/module/services/VoiceService.js +29 -8
  32. package/lib/module/services/telemetry/MobileAI.js +44 -0
  33. package/lib/module/services/telemetry/TelemetryService.js +13 -1
  34. package/lib/module/services/telemetry/TouchAutoCapture.js +44 -18
  35. package/lib/module/specs/FloatingOverlayNativeComponent.ts +19 -0
  36. package/lib/module/support/CSATSurvey.js +95 -12
  37. package/lib/module/support/EscalationSocket.js +70 -1
  38. package/lib/module/support/ReportedIssueEventSource.js +148 -0
  39. package/lib/module/support/escalateTool.js +4 -2
  40. package/lib/module/support/index.js +1 -0
  41. package/lib/module/support/reportIssueTool.js +127 -0
  42. package/lib/module/support/supportPrompt.js +77 -9
  43. package/lib/module/tools/guideTool.js +2 -1
  44. package/lib/module/tools/longPressTool.js +4 -3
  45. package/lib/module/tools/pickerTool.js +6 -4
  46. package/lib/module/tools/tapTool.js +12 -3
  47. package/lib/module/tools/typeTool.js +19 -10
  48. package/lib/module/utils/logger.js +175 -6
  49. package/lib/typescript/react-native.config.d.ts +11 -0
  50. package/lib/typescript/src/components/AIAgent.d.ts +28 -2
  51. package/lib/typescript/src/components/AIConsentDialog.d.ts +153 -0
  52. package/lib/typescript/src/components/AgentChatBar.d.ts +15 -2
  53. package/lib/typescript/src/components/DiscoveryTooltip.d.ts +3 -1
  54. package/lib/typescript/src/components/FloatingOverlayWrapper.d.ts +51 -0
  55. package/lib/typescript/src/components/Icons.d.ts +8 -0
  56. package/lib/typescript/src/config/endpoints.d.ts +5 -3
  57. package/lib/typescript/src/core/AgentRuntime.d.ts +4 -0
  58. package/lib/typescript/src/core/FiberAdapter.d.ts +25 -0
  59. package/lib/typescript/src/core/FiberTreeWalker.d.ts +2 -0
  60. package/lib/typescript/src/core/IdleDetector.d.ts +11 -0
  61. package/lib/typescript/src/core/NativeAlertInterceptor.d.ts +55 -0
  62. package/lib/typescript/src/core/types.d.ts +106 -1
  63. package/lib/typescript/src/index.d.ts +9 -4
  64. package/lib/typescript/src/providers/GeminiProvider.d.ts +6 -5
  65. package/lib/typescript/src/services/ConversationService.d.ts +55 -0
  66. package/lib/typescript/src/services/MobileAIKnowledgeRetriever.d.ts +9 -0
  67. package/lib/typescript/src/services/telemetry/MobileAI.d.ts +7 -0
  68. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +1 -1
  69. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts +9 -6
  70. package/lib/typescript/src/services/telemetry/types.d.ts +3 -1
  71. package/lib/typescript/src/specs/FloatingOverlayNativeComponent.d.ts +17 -0
  72. package/lib/typescript/src/support/EscalationSocket.d.ts +17 -0
  73. package/lib/typescript/src/support/ReportedIssueEventSource.d.ts +24 -0
  74. package/lib/typescript/src/support/escalateTool.d.ts +5 -0
  75. package/lib/typescript/src/support/index.d.ts +2 -1
  76. package/lib/typescript/src/support/reportIssueTool.d.ts +20 -0
  77. package/lib/typescript/src/support/types.d.ts +56 -1
  78. package/lib/typescript/src/utils/logger.d.ts +15 -0
  79. package/package.json +20 -9
  80. package/react-native.config.js +12 -0
  81. package/lib/module/__cli_tmp__.js.map +0 -1
  82. package/lib/module/components/AIAgent.js.map +0 -1
  83. package/lib/module/components/AIZone.js.map +0 -1
  84. package/lib/module/components/AgentChatBar.js.map +0 -1
  85. package/lib/module/components/AgentErrorBoundary.js.map +0 -1
  86. package/lib/module/components/AgentOverlay.js.map +0 -1
  87. package/lib/module/components/DiscoveryTooltip.js.map +0 -1
  88. package/lib/module/components/HighlightOverlay.js.map +0 -1
  89. package/lib/module/components/Icons.js.map +0 -1
  90. package/lib/module/components/ProactiveHint.js.map +0 -1
  91. package/lib/module/components/cards/InfoCard.js.map +0 -1
  92. package/lib/module/components/cards/ReviewSummary.js.map +0 -1
  93. package/lib/module/config/endpoints.js.map +0 -1
  94. package/lib/module/core/ActionRegistry.js.map +0 -1
  95. package/lib/module/core/AgentRuntime.js.map +0 -1
  96. package/lib/module/core/FiberTreeWalker.js.map +0 -1
  97. package/lib/module/core/IdleDetector.js.map +0 -1
  98. package/lib/module/core/MCPBridge.js.map +0 -1
  99. package/lib/module/core/ScreenDehydrator.js.map +0 -1
  100. package/lib/module/core/ZoneRegistry.js.map +0 -1
  101. package/lib/module/core/systemPrompt.js.map +0 -1
  102. package/lib/module/core/types.js.map +0 -1
  103. package/lib/module/hooks/useAction.js.map +0 -1
  104. package/lib/module/index.js.map +0 -1
  105. package/lib/module/plugin/withAppIntents.js.map +0 -1
  106. package/lib/module/providers/GeminiProvider.js.map +0 -1
  107. package/lib/module/providers/OpenAIProvider.js.map +0 -1
  108. package/lib/module/providers/ProviderFactory.js.map +0 -1
  109. package/lib/module/services/AudioInputService.js.map +0 -1
  110. package/lib/module/services/AudioOutputService.js.map +0 -1
  111. package/lib/module/services/KnowledgeBaseService.js.map +0 -1
  112. package/lib/module/services/VoiceService.js.map +0 -1
  113. package/lib/module/services/flags/FlagService.js.map +0 -1
  114. package/lib/module/services/telemetry/MobileAI.js.map +0 -1
  115. package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
  116. package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
  117. package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
  118. package/lib/module/services/telemetry/device.js.map +0 -1
  119. package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
  120. package/lib/module/services/telemetry/index.js.map +0 -1
  121. package/lib/module/services/telemetry/types.js.map +0 -1
  122. package/lib/module/support/CSATSurvey.js.map +0 -1
  123. package/lib/module/support/EscalationEventSource.js.map +0 -1
  124. package/lib/module/support/EscalationSocket.js.map +0 -1
  125. package/lib/module/support/SupportChatModal.js.map +0 -1
  126. package/lib/module/support/SupportGreeting.js.map +0 -1
  127. package/lib/module/support/TicketStore.js.map +0 -1
  128. package/lib/module/support/escalateTool.js.map +0 -1
  129. package/lib/module/support/index.js.map +0 -1
  130. package/lib/module/support/supportPrompt.js.map +0 -1
  131. package/lib/module/support/types.js.map +0 -1
  132. package/lib/module/tools/datePickerTool.js.map +0 -1
  133. package/lib/module/tools/guideTool.js.map +0 -1
  134. package/lib/module/tools/index.js.map +0 -1
  135. package/lib/module/tools/keyboardTool.js.map +0 -1
  136. package/lib/module/tools/longPressTool.js.map +0 -1
  137. package/lib/module/tools/pickerTool.js.map +0 -1
  138. package/lib/module/tools/restoreTool.js.map +0 -1
  139. package/lib/module/tools/scrollTool.js.map +0 -1
  140. package/lib/module/tools/simplifyTool.js.map +0 -1
  141. package/lib/module/tools/sliderTool.js.map +0 -1
  142. package/lib/module/tools/tapTool.js.map +0 -1
  143. package/lib/module/tools/typeTool.js.map +0 -1
  144. package/lib/module/tools/types.js.map +0 -1
  145. package/lib/module/types/jsx.d.js.map +0 -1
  146. package/lib/module/utils/audioUtils.js.map +0 -1
  147. package/lib/module/utils/logger.js.map +0 -1
  148. package/lib/typescript/babel.config.d.ts.map +0 -1
  149. package/lib/typescript/bin/generate-map.d.cts.map +0 -1
  150. package/lib/typescript/eslint.config.d.mts.map +0 -1
  151. package/lib/typescript/generate-map.d.ts.map +0 -1
  152. package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
  153. package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
  154. package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
  155. package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
  156. package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
  157. package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
  158. package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
  159. package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
  160. package/lib/typescript/src/components/Icons.d.ts.map +0 -1
  161. package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
  162. package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
  163. package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
  164. package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
  165. package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
  166. package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
  167. package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
  168. package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
  169. package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
  170. package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
  171. package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
  172. package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
  173. package/lib/typescript/src/core/types.d.ts.map +0 -1
  174. package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
  175. package/lib/typescript/src/index.d.ts.map +0 -1
  176. package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
  177. package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
  178. package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
  179. package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
  180. package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
  181. package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
  182. package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
  183. package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
  184. package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
  185. package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
  186. package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
  187. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
  188. package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
  189. package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
  190. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
  191. package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
  192. package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
  193. package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
  194. package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
  195. package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
  196. package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
  197. package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
  198. package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
  199. package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
  200. package/lib/typescript/src/support/index.d.ts.map +0 -1
  201. package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
  202. package/lib/typescript/src/support/types.d.ts.map +0 -1
  203. package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
  204. package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
  205. package/lib/typescript/src/tools/index.d.ts.map +0 -1
  206. package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
  207. package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
  208. package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
  209. package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
  210. package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
  211. package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
  212. package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
  213. package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
  214. package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
  215. package/lib/typescript/src/tools/types.d.ts.map +0 -1
  216. package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
  217. package/lib/typescript/src/utils/logger.d.ts.map +0 -1
  218. package/src/__cli_tmp__.tsx +0 -9
  219. package/src/cli/analyzers/chain-analyzer.ts +0 -183
  220. package/src/cli/extractors/ai-extractor.ts +0 -6
  221. package/src/cli/extractors/ast-extractor.ts +0 -551
  222. package/src/cli/generate-intents.ts +0 -140
  223. package/src/cli/generate-map.ts +0 -121
  224. package/src/cli/generate-swift.ts +0 -116
  225. package/src/cli/scanners/expo-scanner.ts +0 -203
  226. package/src/cli/scanners/rn-scanner.ts +0 -445
  227. package/src/components/AIAgent.tsx +0 -1716
  228. package/src/components/AIZone.tsx +0 -147
  229. package/src/components/AgentChatBar.tsx +0 -1143
  230. package/src/components/AgentErrorBoundary.tsx +0 -78
  231. package/src/components/AgentOverlay.tsx +0 -73
  232. package/src/components/DiscoveryTooltip.tsx +0 -148
  233. package/src/components/HighlightOverlay.tsx +0 -136
  234. package/src/components/Icons.tsx +0 -253
  235. package/src/components/ProactiveHint.tsx +0 -145
  236. package/src/components/cards/InfoCard.tsx +0 -58
  237. package/src/components/cards/ReviewSummary.tsx +0 -76
  238. package/src/config/endpoints.ts +0 -22
  239. package/src/core/ActionRegistry.ts +0 -105
  240. package/src/core/AgentRuntime.ts +0 -1471
  241. package/src/core/FiberTreeWalker.ts +0 -930
  242. package/src/core/IdleDetector.ts +0 -72
  243. package/src/core/MCPBridge.ts +0 -163
  244. package/src/core/ScreenDehydrator.ts +0 -53
  245. package/src/core/ZoneRegistry.ts +0 -44
  246. package/src/core/systemPrompt.ts +0 -431
  247. package/src/core/types.ts +0 -521
  248. package/src/hooks/useAction.ts +0 -182
  249. package/src/index.ts +0 -83
  250. package/src/plugin/withAppIntents.ts +0 -98
  251. package/src/providers/GeminiProvider.ts +0 -357
  252. package/src/providers/OpenAIProvider.ts +0 -379
  253. package/src/providers/ProviderFactory.ts +0 -36
  254. package/src/services/AudioInputService.ts +0 -226
  255. package/src/services/AudioOutputService.ts +0 -236
  256. package/src/services/KnowledgeBaseService.ts +0 -156
  257. package/src/services/VoiceService.ts +0 -451
  258. package/src/services/flags/FlagService.ts +0 -137
  259. package/src/services/telemetry/MobileAI.ts +0 -66
  260. package/src/services/telemetry/PiiScrubber.ts +0 -17
  261. package/src/services/telemetry/TelemetryService.ts +0 -323
  262. package/src/services/telemetry/TouchAutoCapture.ts +0 -165
  263. package/src/services/telemetry/device.ts +0 -93
  264. package/src/services/telemetry/deviceMetadata.ts +0 -13
  265. package/src/services/telemetry/index.ts +0 -13
  266. package/src/services/telemetry/types.ts +0 -75
  267. package/src/support/CSATSurvey.tsx +0 -304
  268. package/src/support/EscalationEventSource.ts +0 -190
  269. package/src/support/EscalationSocket.ts +0 -152
  270. package/src/support/SupportChatModal.tsx +0 -563
  271. package/src/support/SupportGreeting.tsx +0 -161
  272. package/src/support/TicketStore.ts +0 -100
  273. package/src/support/escalateTool.ts +0 -174
  274. package/src/support/index.ts +0 -29
  275. package/src/support/supportPrompt.ts +0 -55
  276. package/src/support/types.ts +0 -155
  277. package/src/tools/datePickerTool.ts +0 -60
  278. package/src/tools/guideTool.ts +0 -76
  279. package/src/tools/index.ts +0 -20
  280. package/src/tools/keyboardTool.ts +0 -30
  281. package/src/tools/longPressTool.ts +0 -61
  282. package/src/tools/pickerTool.ts +0 -115
  283. package/src/tools/restoreTool.ts +0 -33
  284. package/src/tools/scrollTool.ts +0 -156
  285. package/src/tools/simplifyTool.ts +0 -33
  286. package/src/tools/sliderTool.ts +0 -65
  287. package/src/tools/tapTool.ts +0 -93
  288. package/src/tools/typeTool.ts +0 -113
  289. package/src/tools/types.ts +0 -58
  290. package/src/types/jsx.d.ts +0 -20
  291. package/src/utils/audioUtils.ts +0 -54
  292. package/src/utils/logger.ts +0 -38
package/src/index.ts DELETED
@@ -1,83 +0,0 @@
1
- /**
2
- * @mobileai/react-native
3
- *
4
- * Zero-wrapper AI agent for React Native.
5
- * Auto-detects interactive elements via React Fiber tree traversal.
6
- */
7
-
8
- // ─── Components ──────────────────────────────────────────────
9
- export { AIAgent } from './components/AIAgent';
10
- export { AIZone } from './components/AIZone';
11
- // Built-in card templates for AIZone injection
12
- // Note: displayName is set explicitly on each — required for minification-safe template lookup.
13
- export { InfoCard } from './components/cards/InfoCard';
14
- export { ReviewSummary } from './components/cards/ReviewSummary';
15
-
16
- // ─── Providers ───────────────────────────────────────────────
17
- export { GeminiProvider } from './providers/GeminiProvider';
18
- export { OpenAIProvider } from './providers/OpenAIProvider';
19
- export { createProvider } from './providers/ProviderFactory';
20
-
21
- // ─── Hooks ───────────────────────────────────────────────────
22
- export { useAction, useAI } from './hooks/useAction';
23
-
24
- // ─── Services ────────────────────────────────────────────────
25
- export { VoiceService } from './services/VoiceService';
26
- export { AudioInputService } from './services/AudioInputService';
27
- export { AudioOutputService } from './services/AudioOutputService';
28
- export { KnowledgeBaseService } from './services/KnowledgeBaseService';
29
-
30
- // ─── Analytics ───────────────────────────────────────────────
31
- export { MobileAI } from './services/telemetry';
32
-
33
- // ─── Utilities ───────────────────────────────────────────────
34
- export { logger } from './utils/logger';
35
-
36
- // ─── Types ───────────────────────────────────────────────────
37
- export type {
38
- AgentConfig,
39
- AgentMode,
40
- ExecutionResult,
41
- InteractiveElement,
42
- DehydratedScreen,
43
- ToolDefinition,
44
- ActionDefinition,
45
- TokenUsage,
46
- KnowledgeEntry,
47
- KnowledgeRetriever,
48
- KnowledgeBaseConfig,
49
- ChatBarTheme,
50
- AIMessage,
51
- AIProviderName,
52
- ScreenMap,
53
- ScreenMapEntry,
54
- InteractionMode,
55
- } from './core/types';
56
-
57
- export type {
58
- VoiceServiceConfig,
59
- VoiceServiceCallbacks,
60
- VoiceStatus,
61
- } from './services/VoiceService';
62
-
63
- export type {
64
- TelemetryConfig,
65
- TelemetryEvent,
66
- } from './services/telemetry';
67
-
68
- // ─── Support Mode ────────────────────────────────────────────
69
- // SupportGreeting, CSATSurvey, buildSupportPrompt work standalone (no backend)
70
- // createEscalateTool works with provider='custom' (no backend)
71
- // EscalationSocket and provider='mobileai' require api.mobileai.dev
72
- export { SupportGreeting, CSATSurvey, buildSupportPrompt, createEscalateTool, EscalationSocket } from './support';
73
-
74
- export type {
75
- SupportModeConfig,
76
- QuickReply,
77
- EscalationConfig,
78
- EscalationContext,
79
- CSATConfig,
80
- CSATRating,
81
- BusinessHoursConfig,
82
- SupportTicket,
83
- } from './support';
@@ -1,98 +0,0 @@
1
- import type { ConfigPlugin } from 'expo/config-plugins';
2
- import * as path from 'path';
3
- import * as fs from 'fs';
4
- import { extractIntentsFromAST } from '../cli/generate-intents';
5
- import { generateSwiftCode } from '../cli/generate-swift';
6
-
7
- interface PluginOptions {
8
- /** The source directory to scan for useAction calls. Defaults to 'src' */
9
- scanDirectory?: string;
10
- /** App scheme for deep links. Defaults to the scheme in app.json */
11
- appScheme?: string;
12
- }
13
-
14
- const withAppIntents: ConfigPlugin<PluginOptions | void> = (config, options) => {
15
- let withXcodeProject: ((config: any, action: (config: any) => any) => any) | undefined;
16
- try {
17
- ({ withXcodeProject } = require('expo/config-plugins'));
18
- } catch {
19
- console.warn(
20
- '[MobileAI] `withAppIntents` requires `expo/config-plugins`. ' +
21
- 'Skipping App Intents generation because Expo config plugins are not available.'
22
- );
23
- return config;
24
- }
25
-
26
- if (!withXcodeProject) {
27
- return config;
28
- }
29
-
30
- const applyWithXcodeProject = withXcodeProject;
31
-
32
- return applyWithXcodeProject(config, async (config) => {
33
- const project = config.modResults;
34
- const projectName = config.modRequest.projectName || config.name;
35
- const projectRoot = config.modRequest.projectRoot;
36
-
37
- const scanDir = (options as PluginOptions)?.scanDirectory || 'src';
38
- const appScheme = (options as PluginOptions)?.appScheme || (Array.isArray(config.scheme) ? config.scheme[0] : config.scheme) || 'mobileai';
39
-
40
- try {
41
- // 1. Scan and Extract
42
- const scanPath = path.resolve(projectRoot, scanDir);
43
- console.log(`\n🤖 [MobileAI] Scanning ${scanPath} for AI Actions...`);
44
- const intents = extractIntentsFromAST(scanPath);
45
-
46
- console.log(`🤖 [MobileAI] Found ${intents.length} actions.`);
47
-
48
- // 2. Generate Swift Code
49
- // We write a temporary manifest to disk to use the CLI function,
50
- // or we can just adapt generateSwiftCode to take the object directly,
51
- // but the CLI expects a file path. Let's write a temporary file.
52
- const tmpManifestPath = path.join(projectRoot, '.mobileai-intent-manifest.tmp.json');
53
- fs.writeFileSync(tmpManifestPath, JSON.stringify(intents, null, 2));
54
-
55
- const swiftCode = generateSwiftCode(tmpManifestPath, appScheme);
56
-
57
- // Clean up tmp manifest
58
- if (fs.existsSync(tmpManifestPath)) {
59
- fs.unlinkSync(tmpManifestPath);
60
- }
61
-
62
- // 3. Write Swift File to iOS Project Directory
63
- const targetFilePath = path.join(projectRoot, 'ios', projectName, 'MobileAIAppIntents.swift');
64
-
65
- // Ensure directory exists
66
- const targetDir = path.dirname(targetFilePath);
67
- if (!fs.existsSync(targetDir)) {
68
- fs.mkdirSync(targetDir, { recursive: true });
69
- }
70
-
71
- fs.writeFileSync(targetFilePath, swiftCode);
72
- console.log(`🤖 [MobileAI] Generated ${targetFilePath}`);
73
-
74
- // 4. Link in Xcode
75
- const groupKey = project.findPBXGroupKey({ name: projectName });
76
- if (!groupKey) {
77
- console.warn(`🤖 [MobileAI] Warning: Could not find main PBXGroup for ${projectName}. You may need to manually add MobileAIAppIntents.swift to Xcode.`);
78
- return config;
79
- }
80
-
81
- // Check if already added
82
- const relativeFilePath = `${projectName}/MobileAIAppIntents.swift`;
83
- const fileAdded = project.hasFile(relativeFilePath);
84
-
85
- if (!fileAdded) {
86
- project.addSourceFile(relativeFilePath, null, groupKey);
87
- console.log(`🤖 [MobileAI] Linked MobileAIAppIntents.swift to Xcode project.`);
88
- }
89
-
90
- } catch (error) {
91
- console.error('🤖 [MobileAI] AppIntents generation failed:', error);
92
- }
93
-
94
- return config;
95
- });
96
- };
97
-
98
- export default withAppIntents;
@@ -1,357 +0,0 @@
1
- /**
2
- * GeminiProvider — Gemini API integration via @google/genai SDK.
3
- *
4
- * Uses the official Google GenAI SDK for:
5
- * - generateContent with structured function calling (agent_step)
6
- * - inlineData for vision (base64 screenshots)
7
- * - System instructions
8
- *
9
- * Implements the AIProvider interface so it can be swapped
10
- * with OpenAIProvider, AnthropicProvider, etc.
11
- */
12
-
13
- import { GoogleGenAI, FunctionCallingConfigMode, Type } from '@google/genai';
14
- import { logger } from '../utils/logger';
15
- import type { AIProvider, ToolDefinition, AgentStep, ProviderResult, AgentReasoning, TokenUsage } from '../core/types';
16
-
17
- // ─── Constants ─────────────────────────────────────────────────
18
-
19
- const AGENT_STEP_FN = 'agent_step';
20
-
21
- // Reasoning fields always present in the agent_step schema
22
- const REASONING_FIELDS = ['previous_goal_eval', 'memory', 'plan'] as const;
23
-
24
- // ─── Provider ──────────────────────────────────────────────────
25
-
26
- export class GeminiProvider implements AIProvider {
27
- private ai: GoogleGenAI;
28
- private model: string;
29
-
30
- constructor(
31
- apiKey?: string,
32
- model: string = 'gemini-2.5-flash',
33
- proxyUrl?: string,
34
- proxyHeaders?: Record<string, string>
35
- ) {
36
- const config: any = {};
37
-
38
- if (proxyUrl) {
39
- config.apiKey = 'proxy-key'; // Dummy key to bypass local validation
40
- config.httpOptions = {
41
- baseUrl: proxyUrl,
42
- headers: proxyHeaders || {},
43
- };
44
- } else if (apiKey) {
45
- config.apiKey = apiKey;
46
- } else {
47
- throw new Error('[mobileai] You must provide either "apiKey" or "proxyUrl" to AIAgent.');
48
- }
49
-
50
- this.ai = new GoogleGenAI(config);
51
- this.model = model;
52
- }
53
-
54
- async generateContent(
55
- systemPrompt: string,
56
- userMessage: string,
57
- tools: ToolDefinition[],
58
- history: AgentStep[],
59
- screenshot?: string,
60
- ): Promise<ProviderResult> {
61
-
62
- logger.info('GeminiProvider', `Sending request. Model: ${this.model}, Tools: ${tools.length}${screenshot ? ', with screenshot' : ''}`);
63
-
64
- // Build single agent_step function declaration
65
- const agentStepDeclaration = this.buildAgentStepDeclaration(tools);
66
-
67
- // Build contents (user message + optional screenshot)
68
- const contents = this.buildContents(userMessage, history, screenshot);
69
-
70
- const startTime = Date.now();
71
-
72
- try {
73
- const response = await this.ai.models.generateContent({
74
- model: this.model,
75
- contents,
76
- config: {
77
- systemInstruction: systemPrompt,
78
- tools: [{ functionDeclarations: [agentStepDeclaration] }],
79
- toolConfig: {
80
- functionCallingConfig: {
81
- mode: FunctionCallingConfigMode.ANY,
82
- allowedFunctionNames: [AGENT_STEP_FN],
83
- },
84
- },
85
- temperature: 0.2,
86
- maxOutputTokens: 2048,
87
- },
88
- });
89
-
90
- const elapsed = Date.now() - startTime;
91
- logger.info('GeminiProvider', `Response received in ${elapsed}ms`);
92
-
93
- // Extract token usage from SDK response
94
- const tokenUsage = this.extractTokenUsage(response);
95
- if (tokenUsage) {
96
- logger.info('GeminiProvider', `Tokens: ${tokenUsage.promptTokens} in / ${tokenUsage.completionTokens} out / $${tokenUsage.estimatedCostUSD.toFixed(6)}`);
97
- }
98
-
99
- const result = this.parseAgentStepResponse(response, tools);
100
- result.tokenUsage = tokenUsage;
101
- return result;
102
- } catch (error: any) {
103
- logger.error('GeminiProvider', 'Request failed:', error.message);
104
-
105
- if (error.status) {
106
- throw new Error(this.formatProviderError(error.status, error.message));
107
- }
108
- throw error;
109
- }
110
- }
111
-
112
- // ─── Build agent_step Declaration ──────────────────────────
113
-
114
- /**
115
- * Builds a single `agent_step` function declaration that combines:
116
- * - Structured reasoning fields (previous_goal_eval, memory, plan)
117
- * - action_name (enum of all available tool names)
118
- * - All tool parameter fields as flat top-level properties
119
- *
120
- * Flat schema avoids Gemini's "deeply nested schema" rejection in ANY mode.
121
- */
122
- private buildAgentStepDeclaration(tools: ToolDefinition[]): any {
123
- const toolNames = tools.map(t => t.name);
124
-
125
- // Collect all unique parameter fields across all tools
126
- const actionProperties: Record<string, any> = {};
127
- for (const tool of tools) {
128
- for (const [paramName, param] of Object.entries(tool.parameters)) {
129
- if (actionProperties[paramName]) continue;
130
- actionProperties[paramName] = {
131
- type: this.mapParamType(param.type),
132
- description: param.description,
133
- ...(param.enum ? { enum: param.enum } : {}),
134
- };
135
- }
136
- }
137
-
138
- // Build tool descriptions for the action_name enum
139
- const toolDescriptions = tools
140
- .map(t => {
141
- const params = Object.keys(t.parameters).join(', ');
142
- return `- ${t.name}(${params}): ${t.description}`;
143
- })
144
- .join('\n');
145
-
146
- return {
147
- name: AGENT_STEP_FN,
148
- description: `Execute one agent step. Choose an action and provide reasoning.\n\nAvailable actions:\n${toolDescriptions}`,
149
- parameters: {
150
- type: Type.OBJECT,
151
- properties: {
152
- previous_goal_eval: {
153
- type: Type.STRING,
154
- description: 'One-sentence assessment of your last action. State success, failure, or uncertain. Skip on first step.',
155
- },
156
- memory: {
157
- type: Type.STRING,
158
- description: 'Key facts to remember for future steps: progress made, items found, counters, field values already collected.',
159
- },
160
- plan: {
161
- type: Type.STRING,
162
- description: 'Your immediate next goal — what action you will take and why.',
163
- },
164
- action_name: {
165
- type: Type.STRING,
166
- description: 'Which action to execute.',
167
- enum: toolNames,
168
- },
169
- ...actionProperties,
170
- },
171
- required: ['plan', 'action_name'],
172
- },
173
- };
174
- }
175
-
176
- private mapParamType(type: string): string {
177
- switch (type) {
178
- case 'number': return Type.NUMBER;
179
- case 'integer': return Type.INTEGER;
180
- case 'boolean': return Type.BOOLEAN;
181
- case 'string':
182
- default: return Type.STRING;
183
- }
184
- }
185
-
186
- // ─── Build Contents ────────────────────────────────────────
187
-
188
- /**
189
- * Builds contents for the generateContent call.
190
- * Single-turn: user message + optional screenshot as inlineData.
191
- */
192
- private buildContents(userMessage: string, _history: AgentStep[], screenshot?: string): any[] {
193
- const parts: any[] = [{ text: userMessage }];
194
-
195
- // Append screenshot as inlineData for Gemini vision
196
- if (screenshot) {
197
- parts.push({
198
- inlineData: {
199
- mimeType: 'image/jpeg',
200
- data: screenshot,
201
- },
202
- });
203
- }
204
-
205
- return [{ role: 'user', parts }];
206
- }
207
-
208
- // ─── Parse Response ────────────────────────────────────────
209
-
210
- /**
211
- * Parses the SDK response expecting a single agent_step function call.
212
- * Extracts structured reasoning + action.
213
- */
214
- private parseAgentStepResponse(response: any, tools: ToolDefinition[]): ProviderResult {
215
- const candidates = response.candidates || [];
216
-
217
- if (candidates.length === 0) {
218
- logger.warn('GeminiProvider', 'No candidates in response');
219
- return {
220
- toolCalls: [{ name: 'done', args: { text: 'No response generated.', success: false } }],
221
- reasoning: { previousGoalEval: '', memory: '', plan: '' },
222
- text: 'No response generated.',
223
- };
224
- }
225
-
226
- const candidate = candidates[0];
227
- const parts = candidate.content?.parts || [];
228
-
229
- // Find the function call part
230
- const fnCallPart = parts.find((p: any) => p.functionCall);
231
- const textPart = parts.find((p: any) => p.text);
232
-
233
- if (!fnCallPart?.functionCall) {
234
- logger.warn('GeminiProvider', 'No function call in response. Text:', textPart?.text);
235
- return {
236
- toolCalls: [{ name: 'done', args: { text: textPart?.text || 'No action taken.', success: false } }],
237
- reasoning: { previousGoalEval: '', memory: '', plan: '' },
238
- text: textPart?.text,
239
- };
240
- }
241
-
242
- const args = fnCallPart.functionCall.args || {};
243
-
244
- // Extract reasoning fields
245
- const reasoning: AgentReasoning = {
246
- previousGoalEval: args.previous_goal_eval || '',
247
- memory: args.memory || '',
248
- plan: args.plan || '',
249
- };
250
-
251
- // Extract action
252
- const actionName = args.action_name;
253
- if (!actionName) {
254
- logger.warn('GeminiProvider', 'No action_name in agent_step. Falling back to done.');
255
- return {
256
- toolCalls: [{ name: 'done', args: { text: 'Agent did not choose an action.', success: false } }],
257
- reasoning,
258
- text: textPart?.text,
259
- };
260
- }
261
-
262
- // Build action args: extract only the params that belong to the matched tool
263
- const actionArgs: Record<string, any> = {};
264
- const reservedKeys = new Set([...REASONING_FIELDS, 'action_name']);
265
-
266
- const matchedTool = tools.find(t => t.name === actionName);
267
- if (matchedTool) {
268
- for (const paramName of Object.keys(matchedTool.parameters)) {
269
- if (args[paramName] !== undefined) {
270
- actionArgs[paramName] = args[paramName];
271
- }
272
- }
273
- } else {
274
- for (const [key, value] of Object.entries(args)) {
275
- if (!reservedKeys.has(key)) {
276
- actionArgs[key] = value;
277
- }
278
- }
279
- }
280
-
281
- logger.info('GeminiProvider', `Parsed: action=${actionName}, plan="${reasoning.plan}"`);
282
-
283
- return {
284
- toolCalls: [{ name: actionName, args: actionArgs }],
285
- reasoning,
286
- text: textPart?.text,
287
- };
288
- }
289
-
290
- // ─── Token Usage Extraction ─────────────────────────────────
291
-
292
- /**
293
- * Extracts token usage from SDK response and calculates estimated cost.
294
- *
295
- * Pricing (Gemini 2.5 Flash):
296
- * - Input: $0.30 / 1M tokens
297
- * - Output: $2.50 / 1M tokens
298
- */
299
- private extractTokenUsage(response: any): TokenUsage | undefined {
300
- const meta = response?.usageMetadata;
301
- if (!meta) return undefined;
302
-
303
- const promptTokens = meta.promptTokenCount ?? 0;
304
- const completionTokens = meta.candidatesTokenCount ?? 0;
305
- const totalTokens = meta.totalTokenCount ?? (promptTokens + completionTokens);
306
-
307
- // Cost estimation based on Gemini 2.5 Flash pricing
308
- const INPUT_COST_PER_M = 0.30;
309
- const OUTPUT_COST_PER_M = 2.50;
310
-
311
- const estimatedCostUSD =
312
- (promptTokens / 1_000_000) * INPUT_COST_PER_M +
313
- (completionTokens / 1_000_000) * OUTPUT_COST_PER_M;
314
-
315
- return { promptTokens, completionTokens, totalTokens, estimatedCostUSD };
316
- }
317
-
318
- // ─── Error Formatting ──────────────────────────────────────
319
-
320
- /**
321
- * Converts raw API errors into clean, user-friendly messages.
322
- * Parses JSON error bodies and maps HTTP codes to plain language.
323
- */
324
- private formatProviderError(status: number, rawMessage: string): string {
325
- // Try to extract the human-readable message from JSON body
326
- let humanMessage = '';
327
- try {
328
- const parsed = JSON.parse(rawMessage);
329
- humanMessage = parsed?.error?.message || parsed?.message || '';
330
- } catch {
331
- // rawMessage may contain JSON embedded in a string like "503: {json}"
332
- const jsonMatch = rawMessage.match(/\{[\s\S]*\}/);
333
- if (jsonMatch) {
334
- try {
335
- const parsed = JSON.parse(jsonMatch[0]);
336
- humanMessage = parsed?.error?.message || parsed?.message || '';
337
- } catch { /* ignore */ }
338
- }
339
- }
340
-
341
- // Map status codes to friendly descriptions
342
- switch (status) {
343
- case 429:
344
- return humanMessage || 'Too many requests. Please wait a moment and try again.';
345
- case 503:
346
- return humanMessage || 'The AI service is temporarily unavailable. Please try again shortly.';
347
- case 500:
348
- return humanMessage || 'The AI service encountered an internal error. Please try again.';
349
- case 401:
350
- return 'Authentication failed. Please check your API key.';
351
- case 403:
352
- return 'Access denied. Your API key may not have the required permissions.';
353
- default:
354
- return humanMessage || `Something went wrong (${status}). Please try again.`;
355
- }
356
- }
357
- }