@mobileai/react-native 0.9.10 → 0.9.12

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 (86) hide show
  1. package/README.md +11 -0
  2. package/lib/module/components/AIAgent.js +635 -39
  3. package/lib/module/components/AIAgent.js.map +1 -1
  4. package/lib/module/components/AgentChatBar.js +309 -13
  5. package/lib/module/components/AgentChatBar.js.map +1 -1
  6. package/lib/module/config/endpoints.js +22 -0
  7. package/lib/module/config/endpoints.js.map +1 -0
  8. package/lib/module/core/systemPrompt.js +126 -100
  9. package/lib/module/core/systemPrompt.js.map +1 -1
  10. package/lib/module/services/AudioInputService.js +9 -0
  11. package/lib/module/services/AudioInputService.js.map +1 -1
  12. package/lib/module/services/flags/FlagService.js +1 -1
  13. package/lib/module/services/flags/FlagService.js.map +1 -1
  14. package/lib/module/services/telemetry/TelemetryService.js +44 -15
  15. package/lib/module/services/telemetry/TelemetryService.js.map +1 -1
  16. package/lib/module/services/telemetry/device.js +80 -10
  17. package/lib/module/services/telemetry/device.js.map +1 -1
  18. package/lib/module/services/telemetry/deviceMetadata.js +10 -0
  19. package/lib/module/services/telemetry/deviceMetadata.js.map +1 -0
  20. package/lib/module/support/EscalationEventSource.js +168 -0
  21. package/lib/module/support/EscalationEventSource.js.map +1 -0
  22. package/lib/module/support/EscalationSocket.js +46 -7
  23. package/lib/module/support/EscalationSocket.js.map +1 -1
  24. package/lib/module/support/SupportChatModal.js +544 -0
  25. package/lib/module/support/SupportChatModal.js.map +1 -0
  26. package/lib/module/support/TicketStore.js +93 -0
  27. package/lib/module/support/TicketStore.js.map +1 -0
  28. package/lib/module/support/escalateTool.js +45 -13
  29. package/lib/module/support/escalateTool.js.map +1 -1
  30. package/lib/module/support/index.js +2 -0
  31. package/lib/module/support/index.js.map +1 -1
  32. package/lib/typescript/src/components/AIAgent.d.ts +24 -1
  33. package/lib/typescript/src/components/AIAgent.d.ts.map +1 -1
  34. package/lib/typescript/src/components/AgentChatBar.d.ts +24 -2
  35. package/lib/typescript/src/components/AgentChatBar.d.ts.map +1 -1
  36. package/lib/typescript/src/config/endpoints.d.ts +18 -0
  37. package/lib/typescript/src/config/endpoints.d.ts.map +1 -0
  38. package/lib/typescript/src/core/systemPrompt.d.ts +4 -13
  39. package/lib/typescript/src/core/systemPrompt.d.ts.map +1 -1
  40. package/lib/typescript/src/core/types.d.ts +1 -1
  41. package/lib/typescript/src/core/types.d.ts.map +1 -1
  42. package/lib/typescript/src/hooks/useAction.d.ts +2 -2
  43. package/lib/typescript/src/hooks/useAction.d.ts.map +1 -1
  44. package/lib/typescript/src/index.d.ts +1 -1
  45. package/lib/typescript/src/index.d.ts.map +1 -1
  46. package/lib/typescript/src/services/AudioInputService.d.ts.map +1 -1
  47. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +2 -1
  48. package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +1 -1
  49. package/lib/typescript/src/services/telemetry/device.d.ts +15 -4
  50. package/lib/typescript/src/services/telemetry/device.d.ts.map +1 -1
  51. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts +6 -0
  52. package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +1 -0
  53. package/lib/typescript/src/support/EscalationEventSource.d.ts +38 -0
  54. package/lib/typescript/src/support/EscalationEventSource.d.ts.map +1 -0
  55. package/lib/typescript/src/support/EscalationSocket.d.ts +7 -1
  56. package/lib/typescript/src/support/EscalationSocket.d.ts.map +1 -1
  57. package/lib/typescript/src/support/SupportChatModal.d.ts +21 -0
  58. package/lib/typescript/src/support/SupportChatModal.d.ts.map +1 -0
  59. package/lib/typescript/src/support/TicketStore.d.ts +34 -0
  60. package/lib/typescript/src/support/TicketStore.d.ts.map +1 -0
  61. package/lib/typescript/src/support/escalateTool.d.ts +16 -1
  62. package/lib/typescript/src/support/escalateTool.d.ts.map +1 -1
  63. package/lib/typescript/src/support/index.d.ts +2 -1
  64. package/lib/typescript/src/support/index.d.ts.map +1 -1
  65. package/lib/typescript/src/support/types.d.ts +15 -0
  66. package/lib/typescript/src/support/types.d.ts.map +1 -1
  67. package/package.json +5 -1
  68. package/src/components/AIAgent.tsx +622 -38
  69. package/src/components/AgentChatBar.tsx +348 -9
  70. package/src/config/endpoints.ts +22 -0
  71. package/src/core/systemPrompt.ts +126 -100
  72. package/src/core/types.ts +1 -1
  73. package/src/hooks/useAction.ts +2 -2
  74. package/src/index.ts +1 -0
  75. package/src/services/AudioInputService.ts +9 -0
  76. package/src/services/flags/FlagService.ts +1 -1
  77. package/src/services/telemetry/TelemetryService.ts +46 -14
  78. package/src/services/telemetry/device.ts +88 -11
  79. package/src/services/telemetry/deviceMetadata.ts +13 -0
  80. package/src/support/EscalationEventSource.ts +190 -0
  81. package/src/support/EscalationSocket.ts +47 -8
  82. package/src/support/SupportChatModal.tsx +563 -0
  83. package/src/support/TicketStore.ts +100 -0
  84. package/src/support/escalateTool.ts +53 -13
  85. package/src/support/index.ts +2 -0
  86. package/src/support/types.ts +14 -0
@@ -18,7 +18,7 @@ import {
18
18
  Platform,
19
19
  useWindowDimensions,
20
20
  } from 'react-native';
21
- import type { ExecutionResult, AgentMode, ChatBarTheme } from '../core/types';
21
+ import type { ExecutionResult, AgentMode, ChatBarTheme, AIMessage } from '../core/types';
22
22
  import {
23
23
  MicIcon,
24
24
  SpeakerIcon,
@@ -28,6 +28,8 @@ import {
28
28
  AIBadge,
29
29
  CloseIcon,
30
30
  } from './Icons';
31
+ import type { SupportTicket } from '../support/types';
32
+ import { logger } from '../utils/logger';
31
33
 
32
34
  // ─── Props ─────────────────────────────────────────────────────
33
35
 
@@ -51,10 +53,31 @@ interface AgentChatBarProps {
51
53
  isAISpeaking?: boolean;
52
54
  /** Voice WebSocket is connected */
53
55
  isVoiceConnected?: boolean;
56
+ /** Live human agent is typing */
57
+ /** Live human agent is typing */
58
+ isAgentTyping?: boolean; // used by SupportChatModal via AIAgent
54
59
  /** Full session cleanup (stop mic, audio, WebSocket, live mode) */
55
60
  onStopSession?: () => void;
56
61
  /** Color theme overrides */
57
62
  theme?: ChatBarTheme;
63
+ /** Active support tickets (for human mode) */
64
+ tickets?: SupportTicket[];
65
+ /** Currently selected ticket ID */
66
+ selectedTicketId?: string | null;
67
+ /** Callback when user selects a ticket */
68
+ onTicketSelect?: (ticketId: string) => void;
69
+ /** Callback when user goes back to ticket list */
70
+ onBackToTickets?: () => void;
71
+ /** Incremented to trigger auto-expand */
72
+ autoExpandTrigger?: number;
73
+ /** Chat messages for selected ticket */
74
+ chatMessages?: AIMessage[];
75
+ /** The user's original typed query — shown in the result bubble instead of agent reasoning */
76
+ lastUserMessage?: string | null;
77
+ /** Unread message counts per ticket (ticketId -> count) */
78
+ unreadCounts?: Record<string, number>;
79
+ /** Total unread messages across all tickets */
80
+ totalUnread?: number;
58
81
  }
59
82
 
60
83
  // ─── Mode Selector ─────────────────────────────────────────────
@@ -63,16 +86,27 @@ function ModeSelector({
63
86
  modes,
64
87
  activeMode,
65
88
  onSelect,
89
+ isArabic = false,
90
+ totalUnread = 0,
66
91
  }: {
67
92
  modes: AgentMode[];
68
93
  activeMode: AgentMode;
69
94
  onSelect: (mode: AgentMode) => void;
95
+ isArabic?: boolean;
96
+ totalUnread?: number;
70
97
  }) {
71
98
  if (modes.length <= 1) return null;
72
99
 
73
100
  const labels: Record<AgentMode, { label: string }> = {
74
- text: { label: 'Text' },
75
- voice: { label: 'Live Agent' },
101
+ text: { label: isArabic ? 'نص' : 'Text' },
102
+ voice: { label: isArabic ? 'صوت' : 'Voice' },
103
+ human: { label: isArabic ? 'دعم' : 'Human' },
104
+ };
105
+
106
+ const dotColor: Record<AgentMode, string> = {
107
+ text: '#7B68EE',
108
+ voice: '#34C759',
109
+ human: '#FF9500',
76
110
  };
77
111
 
78
112
  return (
@@ -93,7 +127,7 @@ function ModeSelector({
93
127
  width: 6,
94
128
  height: 6,
95
129
  borderRadius: 3,
96
- backgroundColor: mode === 'voice' ? '#34C759' : '#7B68EE',
130
+ backgroundColor: dotColor[mode],
97
131
  }} />
98
132
  )}
99
133
  <Text
@@ -104,6 +138,14 @@ function ModeSelector({
104
138
  >
105
139
  {labels[mode].label}
106
140
  </Text>
141
+ {/* Unread indicator — inline after label */}
142
+ {mode === 'human' && totalUnread > 0 && (
143
+ <View style={styles.humanTabBadge}>
144
+ <Text style={styles.humanTabBadgeText}>
145
+ {totalUnread > 99 ? '99+' : totalUnread}
146
+ </Text>
147
+ </View>
148
+ )}
107
149
  </Pressable>
108
150
  ))}
109
151
  </View>
@@ -396,12 +438,24 @@ export function AgentChatBar({
396
438
  isVoiceConnected,
397
439
  onStopSession,
398
440
  theme,
441
+ tickets = [],
442
+ selectedTicketId,
443
+ onTicketSelect,
444
+ autoExpandTrigger = 0,
445
+ lastUserMessage,
446
+ unreadCounts = {},
447
+ totalUnread = 0,
399
448
  }: AgentChatBarProps) {
400
449
  const [text, setText] = useState('');
401
450
  const [isExpanded, setIsExpanded] = useState(false);
402
451
  const { height } = useWindowDimensions();
403
452
  const isArabic = language === 'ar';
404
453
 
454
+ // Auto-expand when triggered (e.g. on escalation)
455
+ useEffect(() => {
456
+ if (autoExpandTrigger > 0) setIsExpanded(true);
457
+ }, [autoExpandTrigger]);
458
+
405
459
  const pan = useRef(new Animated.ValueXY({ x: 10, y: height - 200 })).current;
406
460
  const keyboardOffset = useRef(new Animated.Value(0)).current;
407
461
 
@@ -459,6 +513,14 @@ export function AgentChatBar({
459
513
  }
460
514
  };
461
515
 
516
+ // ─── HEAVY DEBUG LOGGING ──────────────────────────────────────
517
+ logger.info('ChatBar', '★★★ RENDER — mode:', mode,
518
+ '| selectedTicketId:', selectedTicketId,
519
+ '| tickets:', tickets.length,
520
+ '| availableModes:', availableModes,
521
+ '| lastResult:', lastResult ? lastResult.message.substring(0, 60) : 'null',
522
+ '| isExpanded:', isExpanded);
523
+
462
524
  // ─── FAB (Compressed) ──────────────────────────────────────
463
525
 
464
526
  if (!isExpanded) {
@@ -470,10 +532,18 @@ export function AgentChatBar({
470
532
  <Pressable
471
533
  style={[styles.fab, theme?.primaryColor ? { backgroundColor: theme.primaryColor } : undefined]}
472
534
  onPress={() => setIsExpanded(true)}
473
- accessibilityLabel="Open AI Agent Chat"
535
+ accessibilityLabel={totalUnread > 0 ? `Open AI Agent Chat - ${totalUnread} unread messages` : 'Open AI Agent Chat'}
474
536
  >
475
537
  {isThinking ? <LoadingDots size={28} color={theme?.textColor || '#fff'} /> : <AIBadge size={28} />}
476
538
  </Pressable>
539
+ {/* Unread badge on collapsed FAB */}
540
+ {totalUnread > 0 && (
541
+ <View style={styles.fabUnreadBadge} pointerEvents="none">
542
+ <Text style={styles.fabUnreadBadgeText}>
543
+ {totalUnread > 99 ? '99+' : totalUnread}
544
+ </Text>
545
+ </View>
546
+ )}
477
547
  </Animated.View>
478
548
  );
479
549
  }
@@ -500,10 +570,12 @@ export function AgentChatBar({
500
570
  modes={availableModes}
501
571
  activeMode={mode}
502
572
  onSelect={(m) => onModeChange?.(m)}
573
+ isArabic={isArabic}
574
+ totalUnread={totalUnread}
503
575
  />
504
576
 
505
- {/* Result Bubble */}
506
- {lastResult && (() => {
577
+ {/* Result Bubble — only show in text/voice modes, NOT in human mode */}
578
+ {lastResult && mode !== 'human' && (() => {
507
579
  const cleanMessage = lastResult.message.trim();
508
580
  return (
509
581
  <View style={[
@@ -512,8 +584,10 @@ export function AgentChatBar({
512
584
  ? [styles.resultSuccess, theme?.successColor ? { backgroundColor: theme.successColor } : undefined]
513
585
  : [styles.resultError, theme?.errorColor ? { backgroundColor: theme.errorColor } : undefined],
514
586
  ]}>
515
- <ScrollView style={styles.resultScroll} nestedScrollEnabled>
516
- <Text style={[styles.resultText, { textAlign: isArabic ? 'right' : 'left' }, theme?.textColor ? { color: theme.textColor } : undefined]}>{cleanMessage}</Text>
587
+ <ScrollView style={styles.resultScroll} nestedScrollEnabled>
588
+ <Text style={[styles.resultText, { textAlign: isArabic ? 'right' : 'left' }, theme?.textColor ? { color: theme.textColor } : undefined]}>
589
+ {lastUserMessage ?? cleanMessage}
590
+ </Text>
517
591
  </ScrollView>
518
592
  {onDismiss && (
519
593
  <Pressable style={styles.dismissButton} onPress={onDismiss} hitSlop={12}>
@@ -536,6 +610,46 @@ export function AgentChatBar({
536
610
  />
537
611
  )}
538
612
 
613
+ {/* Human mode: ticket list or chat */}
614
+ {mode === 'human' && !selectedTicketId && (
615
+ <ScrollView style={styles.ticketList} nestedScrollEnabled>
616
+ {tickets.length === 0 ? (
617
+ <Text style={styles.emptyText}>No active tickets</Text>
618
+ ) : (
619
+ tickets.map(ticket => {
620
+ const unreadCount = unreadCounts[ticket.id] || 0;
621
+ return (
622
+ <Pressable
623
+ key={ticket.id}
624
+ style={styles.ticketCard}
625
+ onPress={() => onTicketSelect?.(ticket.id)}
626
+ >
627
+ <View style={styles.ticketTopRow}>
628
+ <Text style={styles.ticketReason} numberOfLines={2}>
629
+ {ticket.history.length > 0 ? (ticket.history[ticket.history.length - 1]?.content ?? ticket.reason) : ticket.reason}
630
+ </Text>
631
+ {unreadCount > 0 && (
632
+ <View style={styles.unreadBadge}>
633
+ <Text style={styles.unreadBadgeText}>
634
+ {unreadCount > 99 ? '99+' : unreadCount}
635
+ </Text>
636
+ </View>
637
+ )}
638
+ </View>
639
+ <View style={styles.ticketMeta}>
640
+ <Text style={[styles.ticketStatus, ticket.status === 'open' && styles.statusOpen]}>
641
+ {ticket.status}
642
+ </Text>
643
+ </View>
644
+ </Pressable>
645
+ );
646
+ })
647
+ )}
648
+ </ScrollView>
649
+ )}
650
+
651
+ {mode === 'human' && selectedTicketId && null}
652
+
539
653
  {mode === 'voice' && (
540
654
  <VoiceControlsRow
541
655
  isMicActive={isMicActive}
@@ -549,6 +663,7 @@ export function AgentChatBar({
549
663
  />
550
664
  )}
551
665
 
666
+ {/* Voice controls removed since mode handles it */}
552
667
 
553
668
  </Animated.View>
554
669
  );
@@ -693,6 +808,145 @@ const styles = StyleSheet.create({
693
808
  dictationButtonActive: {
694
809
  backgroundColor: 'rgba(255, 59, 48, 0.3)',
695
810
  },
811
+ ticketList: {
812
+ maxHeight: 260,
813
+ paddingHorizontal: 12,
814
+ },
815
+ ticketCard: {
816
+ backgroundColor: 'rgba(255, 255, 255, 0.08)',
817
+ borderRadius: 12,
818
+ padding: 14,
819
+ marginBottom: 8,
820
+ },
821
+ ticketTopRow: {
822
+ flexDirection: 'row',
823
+ alignItems: 'flex-start',
824
+ justifyContent: 'space-between',
825
+ gap: 8,
826
+ },
827
+ ticketReason: {
828
+ color: '#fff',
829
+ fontSize: 14,
830
+ fontWeight: '600',
831
+ flex: 1,
832
+ },
833
+ ticketMeta: {
834
+ flexDirection: 'row',
835
+ justifyContent: 'space-between',
836
+ alignItems: 'center',
837
+ marginTop: 6,
838
+ },
839
+
840
+ ticketStatus: {
841
+ fontSize: 11,
842
+ fontWeight: '600',
843
+ color: 'rgba(255, 255, 255, 0.5)',
844
+ },
845
+ statusOpen: {
846
+ color: '#FF9500',
847
+ },
848
+ emptyText: {
849
+ color: 'rgba(255, 255, 255, 0.4)',
850
+ fontSize: 14,
851
+ textAlign: 'center',
852
+ paddingVertical: 30,
853
+ },
854
+ backBtn: {
855
+ paddingHorizontal: 16,
856
+ paddingVertical: 10,
857
+ },
858
+ backBtnText: {
859
+ color: '#7B68EE',
860
+ fontSize: 14,
861
+ fontWeight: '600',
862
+ },
863
+ chatMessages: {
864
+ maxHeight: 200,
865
+ paddingHorizontal: 12,
866
+ marginBottom: 8,
867
+ },
868
+ msgBubble: {
869
+ borderRadius: 12,
870
+ padding: 10,
871
+ marginBottom: 6,
872
+ maxWidth: '85%',
873
+ },
874
+ msgBubbleUser: {
875
+ backgroundColor: 'rgba(123, 104, 238, 0.3)',
876
+ alignSelf: 'flex-end',
877
+ },
878
+ msgBubbleAgent: {
879
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
880
+ alignSelf: 'flex-start',
881
+ },
882
+ msgText: {
883
+ color: '#fff',
884
+ fontSize: 13,
885
+ lineHeight: 18,
886
+ },
887
+ typingIndicator: {
888
+ paddingHorizontal: 16,
889
+ paddingBottom: 6,
890
+ },
891
+ typingText: {
892
+ fontSize: 12,
893
+ color: 'rgba(255, 255, 255, 0.4)',
894
+ fontStyle: 'italic',
895
+ },
896
+ unreadBadge: {
897
+ minWidth: 16,
898
+ height: 16,
899
+ borderRadius: 8,
900
+ backgroundColor: '#FF3B30',
901
+ justifyContent: 'center',
902
+ alignItems: 'center',
903
+ paddingHorizontal: 4,
904
+ },
905
+ unreadBadgeText: {
906
+ color: '#fff',
907
+ fontSize: 10,
908
+ fontWeight: '700',
909
+ lineHeight: 16,
910
+ textAlign: 'center',
911
+ },
912
+ humanTabBadge: {
913
+ minWidth: 14,
914
+ height: 14,
915
+ borderRadius: 7,
916
+ backgroundColor: '#FF3B30',
917
+ justifyContent: 'center',
918
+ alignItems: 'center',
919
+ paddingHorizontal: 3,
920
+ marginLeft: 3,
921
+ },
922
+ humanTabBadgeText: {
923
+ color: '#fff',
924
+ fontSize: 8,
925
+ fontWeight: '700',
926
+ lineHeight: 14,
927
+ textAlign: 'center',
928
+ },
929
+ fabUnreadBadge: {
930
+ position: 'absolute',
931
+ top: -2,
932
+ right: -2,
933
+ minWidth: 20,
934
+ height: 20,
935
+ borderRadius: 10,
936
+ backgroundColor: '#FF3B30',
937
+ justifyContent: 'center',
938
+ alignItems: 'center',
939
+ paddingHorizontal: 5,
940
+ borderWidth: 2,
941
+ borderColor: '#1a1a2e',
942
+ },
943
+ fabUnreadBadgeText: {
944
+ color: '#fff',
945
+ fontSize: 11,
946
+ fontWeight: '700',
947
+ lineHeight: 20,
948
+ textAlign: 'center',
949
+ },
696
950
  });
697
951
 
698
952
  const modeStyles = StyleSheet.create({
@@ -783,4 +1037,89 @@ const audioStyles = StyleSheet.create({
783
1037
  statusDotConnecting: {
784
1038
  backgroundColor: '#FFCC00',
785
1039
  },
1040
+ humanStatusRow: {
1041
+ flexDirection: 'row',
1042
+ alignItems: 'center',
1043
+ justifyContent: 'center',
1044
+ paddingVertical: 10,
1045
+ gap: 8,
1046
+ },
1047
+ humanStatusDot: {
1048
+ width: 8,
1049
+ height: 8,
1050
+ borderRadius: 4,
1051
+ backgroundColor: '#FF9500',
1052
+ },
1053
+ humanStatusText: {
1054
+ color: '#FF9500',
1055
+ fontSize: 13,
1056
+ fontWeight: '600',
1057
+ },
1058
+ ticketList: {
1059
+ maxHeight: 260,
1060
+ paddingHorizontal: 12,
1061
+ },
1062
+ ticketCard: {
1063
+ backgroundColor: 'rgba(255, 255, 255, 0.08)',
1064
+ borderRadius: 12,
1065
+ padding: 14,
1066
+ marginBottom: 8,
1067
+ },
1068
+ ticketReason: {
1069
+ color: '#fff',
1070
+ fontSize: 14,
1071
+ fontWeight: '600',
1072
+ },
1073
+ ticketMeta: {
1074
+ flexDirection: 'row',
1075
+ justifyContent: 'space-between',
1076
+ alignItems: 'center',
1077
+ marginTop: 6,
1078
+ },
1079
+
1080
+ ticketStatus: {
1081
+ fontSize: 11,
1082
+ fontWeight: '600',
1083
+ color: 'rgba(255, 255, 255, 0.5)',
1084
+ },
1085
+ statusOpen: {
1086
+ color: '#FF9500',
1087
+ },
1088
+ emptyText: {
1089
+ color: 'rgba(255, 255, 255, 0.4)',
1090
+ fontSize: 14,
1091
+ textAlign: 'center',
1092
+ paddingVertical: 30,
1093
+ },
1094
+ backBtn: {
1095
+ paddingHorizontal: 16,
1096
+ paddingVertical: 10,
1097
+ },
1098
+ backBtnText: {
1099
+ color: '#7B68EE',
1100
+ fontSize: 14,
1101
+ fontWeight: '600',
1102
+ },
1103
+ backRow: {
1104
+ flexDirection: 'row',
1105
+ alignItems: 'center',
1106
+ paddingHorizontal: 12,
1107
+ paddingVertical: 8,
1108
+ borderBottomWidth: 1,
1109
+ borderBottomColor: 'rgba(255, 255, 255, 0.08)',
1110
+ },
1111
+ backText: {
1112
+ color: '#7B68EE',
1113
+ fontSize: 14,
1114
+ fontWeight: '600',
1115
+ },
1116
+ emptyTickets: {
1117
+ alignItems: 'center',
1118
+ justifyContent: 'center',
1119
+ paddingVertical: 40,
1120
+ },
1121
+ emptyTicketsText: {
1122
+ color: 'rgba(255, 255, 255, 0.4)',
1123
+ fontSize: 14,
1124
+ },
786
1125
  });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * SDK Endpoint Configuration
3
+ *
4
+ * All MobileAI backend URLs live here.
5
+ * Change these to point to a self-hosted or staging server.
6
+ *
7
+ * Enterprise customers: use the `analyticsProxyUrl` prop on <AIAgent>
8
+ * to route telemetry through your own backend without touching this file.
9
+ */
10
+
11
+ const MOBILEAI_BASE = 'http://localhost:3001';
12
+
13
+ export const ENDPOINTS = {
14
+ /** Telemetry event ingest — receives batched SDK events */
15
+ telemetryIngest: `${MOBILEAI_BASE}/api/v1/events`,
16
+
17
+ /** Feature flag sync — fetches remote flags for this analyticsKey */
18
+ featureFlags: `${MOBILEAI_BASE}/api/v1/flags`,
19
+
20
+ /** Live agent escalation (support handoff) */
21
+ escalation: `${MOBILEAI_BASE}`,
22
+ } as const;