@adminide-stack/yantra-mobile 12.0.28-alpha.8 → 12.0.28-alpha.80

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 (85) hide show
  1. package/lib/api/stt.js +54 -0
  2. package/lib/api/stt.js.map +1 -0
  3. package/lib/assets/icon.png +0 -0
  4. package/lib/components/CustomDrawer.js +479 -0
  5. package/lib/components/CustomDrawer.js.map +1 -0
  6. package/lib/components/GatewayConnector/GatewayConnector.js +18 -0
  7. package/lib/components/GatewayConnector/GatewayConnector.js.map +1 -0
  8. package/lib/components/GatewayToolbarButtonMobile.js +84 -0
  9. package/lib/components/GatewayToolbarButtonMobile.js.map +1 -0
  10. package/lib/components/NavigationHeader/NavigationHeader.js +214 -0
  11. package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -0
  12. package/lib/components/ThinkingIndicator.js +55 -0
  13. package/lib/components/ThinkingIndicator.js.map +1 -0
  14. package/lib/components/YantraBrandLoader.js +94 -0
  15. package/lib/components/YantraBrandLoader.js.map +1 -0
  16. package/lib/compute.js +114 -5
  17. package/lib/compute.js.map +1 -1
  18. package/lib/config/constants.js +18 -0
  19. package/lib/config/constants.js.map +1 -0
  20. package/lib/config/env-config.js +75 -19
  21. package/lib/config/env-config.js.map +1 -1
  22. package/lib/contexts/CdecliConnectionContext.js +47 -0
  23. package/lib/contexts/CdecliConnectionContext.js.map +1 -0
  24. package/lib/contexts/GatewayContext.js +77 -0
  25. package/lib/contexts/GatewayContext.js.map +1 -0
  26. package/lib/features/audio-input/AudioRecorderPanel.js +220 -0
  27. package/lib/features/audio-input/AudioRecorderPanel.js.map +1 -0
  28. package/lib/features/audio-input/MicErrorBoundary.js +34 -0
  29. package/lib/features/audio-input/MicErrorBoundary.js.map +1 -0
  30. package/lib/features/audio-input/useAudioPermission.js +24 -0
  31. package/lib/features/audio-input/useAudioPermission.js.map +1 -0
  32. package/lib/graphql/agentGatewayDocuments.js +53 -0
  33. package/lib/graphql/agentGatewayDocuments.js.map +1 -0
  34. package/lib/hooks/useAccountDefaultSettings.js +38 -0
  35. package/lib/hooks/useAccountDefaultSettings.js.map +1 -0
  36. package/lib/hooks/useCdecliAutoConnect.js +244 -0
  37. package/lib/hooks/useCdecliAutoConnect.js.map +1 -0
  38. package/lib/hooks/useCdecliChannel.js +161 -0
  39. package/lib/hooks/useCdecliChannel.js.map +1 -0
  40. package/lib/hooks/useChatApi.js +390 -171
  41. package/lib/hooks/useChatApi.js.map +1 -1
  42. package/lib/hooks/useChatStream.js +179 -137
  43. package/lib/hooks/useChatStream.js.map +1 -1
  44. package/lib/hooks/useGatewayConnection.js +123 -0
  45. package/lib/hooks/useGatewayConnection.js.map +1 -0
  46. package/lib/hooks/useGatewayRegistry.js +28 -0
  47. package/lib/hooks/useGatewayRegistry.js.map +1 -0
  48. package/lib/hooks/usePrerequisiteIds.js +209 -0
  49. package/lib/hooks/usePrerequisiteIds.js.map +1 -0
  50. package/lib/hooks/useWorkspaceProvisioner.js +236 -0
  51. package/lib/hooks/useWorkspaceProvisioner.js.map +1 -0
  52. package/lib/index.js +1 -1
  53. package/lib/index.js.map +1 -1
  54. package/lib/routes.json +120 -5
  55. package/lib/screens/Chat/index.js +409 -0
  56. package/lib/screens/Chat/index.js.map +1 -0
  57. package/lib/screens/ChatHistory/index.js +56 -0
  58. package/lib/screens/ChatHistory/index.js.map +1 -0
  59. package/lib/screens/Home/HomeScreen.js +364 -144
  60. package/lib/screens/Home/HomeScreen.js.map +1 -1
  61. package/lib/screens/Home/components/ChatHistoryLanding.js +487 -0
  62. package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -0
  63. package/lib/screens/Home/components/DeepSearchModal.js +349 -0
  64. package/lib/screens/Home/components/DeepSearchModal.js.map +1 -0
  65. package/lib/screens/Home/deepSearchUtils.js +41 -0
  66. package/lib/screens/Home/deepSearchUtils.js.map +1 -0
  67. package/lib/screens/NewChat/index.js +43 -0
  68. package/lib/screens/NewChat/index.js.map +1 -0
  69. package/lib/services/agentSessionManager.js +451 -0
  70. package/lib/services/agentSessionManager.js.map +1 -0
  71. package/lib/services/gatewayApiKeyBridge.js +4 -0
  72. package/lib/services/gatewayApiKeyBridge.js.map +1 -0
  73. package/lib/services/gatewayClient.js +470 -0
  74. package/lib/services/gatewayClient.js.map +1 -0
  75. package/lib/theme/mobileTokens.js +18 -0
  76. package/lib/theme/mobileTokens.js.map +1 -0
  77. package/lib/utils/cdecodeUri.js +68 -0
  78. package/lib/utils/cdecodeUri.js.map +1 -0
  79. package/lib/utils/gatewaySelectionStorage.js +21 -0
  80. package/lib/utils/gatewaySelectionStorage.js.map +1 -0
  81. package/lib/utils/syncMobileOrgRouteContext.js +61 -0
  82. package/lib/utils/syncMobileOrgRouteContext.js.map +1 -0
  83. package/package.json +7 -3
  84. package/lib/api/chatApi.js +0 -102
  85. package/lib/api/chatApi.js.map +0 -1
@@ -1,4 +1,6 @@
1
- import {jsx,jsxs}from'react/jsx-runtime';import {useState,useCallback,useEffect}from'react';import {Pressable,StyleSheet}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {SafeAreaView}from'react-native-safe-area-context';import {useGetAccountChatSessionsQuery}from'common/graphql';import {v4}from'uuid';import {useNavigation}from'@react-navigation/native';import {MessagesContainerUI}from'@messenger-box/platform-mobile';import {useChatMutations}from'../../hooks/useChatApi.js';import {useChatStream}from'../../hooks/useChatStream.js';var __defProp = Object.defineProperty;
1
+ import {jsx,jsxs}from'react/jsx-runtime';import React,{useRef,useState,useEffect,useCallback,useMemo}from'react';import {useWindowDimensions,useColorScheme,Platform,Keyboard,TouchableWithoutFeedback,View,StyleSheet,Pressable}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {getDefaultLeftItems,getDefaultRightItems,Box,Text,InputToolBar}from'@admin-layout/gluestack-ui-mobile';import {useSafeAreaInsets,SafeAreaView}from'react-native-safe-area-context';import {useNavigation,useRoute,CommonActions}from'@react-navigation/native';import {useDispatch,useSelector}from'react-redux';import {v4}from'uuid';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {syncMobileOrgRouteContext}from'../../utils/syncMobileOrgRouteContext.js';import {useChatMutations}from'../../hooks/useChatApi.js';import {AudioRecorderPanel}from'../../features/audio-input/AudioRecorderPanel.js';import {MicErrorBoundary}from'../../features/audio-input/MicErrorBoundary.js';import {requestMicPermission}from'../../features/audio-input/useAudioPermission.js';import {mobileTokens}from'../../theme/mobileTokens.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
2
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
4
6
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -14,47 +16,149 @@ var __spreadValues = (a, b) => {
14
16
  }
15
17
  return a;
16
18
  };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ function buildChannelTitle(mode, channelId) {
21
+ return mode === "deep-search" ? `deep-search-${channelId}` : `chat-channel-${channelId}`;
22
+ }
23
+ const EmptyStateSection = React.memo(function EmptyStateSection2({
24
+ isDark,
25
+ secondaryTextColor,
26
+ primaryTextColor,
27
+ activeMode,
28
+ onModeSwitch
29
+ }) {
30
+ return /* @__PURE__ */ jsx(Box, { flex: 1, width: "100%", children: /* @__PURE__ */ jsxs(View, { style: styles.emptyCenterTitleWrap, children: [
31
+ /* @__PURE__ */ jsx(Text, { style: [styles.emptyEyebrow, {
32
+ color: secondaryTextColor
33
+ }], children: "Choose your mode" }),
34
+ /* @__PURE__ */ jsxs(View, { style: [styles.emptyModePillRow, {
35
+ backgroundColor: isDark ? "rgba(30, 41, 59, 0.9)" : "#eef2ff",
36
+ borderColor: isDark ? "rgba(148, 163, 184, 0.26)" : "rgba(67, 56, 202, 0.15)"
37
+ }], children: [
38
+ /* @__PURE__ */ jsxs(Pressable, { onPress: () => onModeSwitch("chat"), style: [styles.emptyModePill, activeMode === "chat" && styles.emptyModePillActive, activeMode === "chat" && {
39
+ backgroundColor: isDark ? "#312e81" : "#4338ca"
40
+ }], accessibilityRole: "button", accessibilityLabel: "Switch to chat mode", children: [
41
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "magnify", size: 14, color: activeMode === "chat" ? "#ffffff" : secondaryTextColor }),
42
+ /* @__PURE__ */ jsx(Text, { style: [styles.emptyModePillLabel, {
43
+ color: activeMode === "chat" ? "#ffffff" : secondaryTextColor
44
+ }], children: "Chat" })
45
+ ] }),
46
+ /* @__PURE__ */ jsxs(Pressable, { onPress: () => onModeSwitch("deep-search"), style: [styles.emptyModePill, activeMode === "deep-search" && styles.emptyModePillActive, activeMode === "deep-search" && {
47
+ backgroundColor: isDark ? "#312e81" : "#4338ca"
48
+ }], accessibilityRole: "button", accessibilityLabel: "Switch to deep-search mode", children: [
49
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "lightning-bolt-outline", size: 14, color: activeMode === "deep-search" ? "#ffffff" : secondaryTextColor }),
50
+ /* @__PURE__ */ jsx(Text, { style: [styles.emptyModePillLabel, {
51
+ color: activeMode === "deep-search" ? "#ffffff" : secondaryTextColor
52
+ }], children: "Deep Search" })
53
+ ] }),
54
+ /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
55
+ console.log("build mode");
56
+ }, style: styles.emptyModePill, accessibilityRole: "button", accessibilityLabel: "Build mode (preview)", children: [
57
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "lightbulb-outline", size: 14, color: secondaryTextColor }),
58
+ /* @__PURE__ */ jsx(Text, { style: [styles.emptyModePillLabel, {
59
+ color: secondaryTextColor
60
+ }], children: "Build" })
61
+ ] })
62
+ ] }),
63
+ /* @__PURE__ */ jsx(Text, { style: [styles.emptyCenterTitle, {
64
+ color: primaryTextColor
65
+ }], children: "How do you want to start?" }),
66
+ /* @__PURE__ */ jsx(Text, { style: [styles.emptySubtitle, {
67
+ color: secondaryTextColor
68
+ }], children: "Use Chat for quick help, Deep Search for source-backed answers, or Build to assemble workflows." })
69
+ ] }) });
70
+ });
17
71
  function HomeScreenContent({
18
72
  initialMode = "chat",
19
73
  onSubmit: onSubmitProp,
20
- onStop,
21
74
  isLoading: isLoadingProp = false,
22
75
  disabled = false
23
76
  }) {
77
+ var _a, _b, _c;
78
+ const {
79
+ width: screenWidth
80
+ } = useWindowDimensions();
81
+ const colorScheme = useColorScheme();
82
+ const isDark = colorScheme === "dark";
24
83
  const navigation = useNavigation();
84
+ const route = useRoute();
85
+ const dispatch = useDispatch();
86
+ const syncedRouteOrgRef = useRef(null);
87
+ const mobileRoutePath = useSelector((state) => {
88
+ var _a2, _b2, _c2;
89
+ return (_c2 = (_b2 = (_a2 = state.router) == null ? void 0 : _a2.location) == null ? void 0 : _b2.currentRoute) == null ? void 0 : _c2.path;
90
+ });
25
91
  const [value, setValue] = useState("");
26
92
  const [activeMode, setActiveMode] = useState(initialMode);
27
- const [activeSessionId, setActiveSessionId] = useState(null);
93
+ const [showAudioRecorder, setShowAudioRecorder] = useState(false);
94
+ const [voiceError, setVoiceError] = useState(null);
28
95
  const {
29
- createSession
96
+ createChannel
30
97
  } = useChatMutations();
31
- const chat = useChatStream(activeSessionId);
32
- useGetAccountChatSessionsQuery({
33
- variables: {
34
- first: 25,
35
- includeArchived: false
36
- },
37
- fetchPolicy: "cache-first"
38
- });
39
98
  const {
40
- messages,
41
- response,
42
- error: chatError,
43
- isLoading: chatLoading,
44
- isStreaming,
45
- hasMessages,
46
- sendMessage,
47
- cancel
48
- } = chat;
99
+ orgName: resolvedOrgName,
100
+ projectId,
101
+ accountUserId,
102
+ loading: prerequisitesLoading,
103
+ orgLoading
104
+ } = usePrerequisiteIds();
105
+ const routeOrgName = ((_b = (_a = route == null ? void 0 : route.params) == null ? void 0 : _a.orgName) != null ? _b : "").trim() || null;
106
+ const effectiveOrgName = resolvedOrgName || routeOrgName || null;
107
+ const effectiveProjectId = projectId || null;
49
108
  const trimmedQuery = value.trim();
50
109
  const hasQuery = trimmedQuery.length > 0;
51
- const canSubmit = hasQuery;
52
- const isLoading = isLoadingProp || chatLoading;
110
+ const canSubmit = hasQuery && Boolean(routeOrgName || effectiveOrgName);
111
+ const isLoading = isLoadingProp;
53
112
  const isResearchMode = activeMode === "deep-search";
54
- const inputPlaceholder = isResearchMode ? "Research anything..." : "Ask anything...";
113
+ const inputPlaceholder = !effectiveOrgName ? "Initializing workspace..." : isResearchMode ? "Research anything..." : "Ask anything...";
114
+ const insets = useSafeAreaInsets();
115
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
116
+ useEffect(() => {
117
+ if (Platform.OS === "ios") {
118
+ const frameSub = Keyboard.addListener("keyboardWillChangeFrame", (event) => {
119
+ var _a2, _b2;
120
+ return setKeyboardHeight((_b2 = (_a2 = event.endCoordinates) == null ? void 0 : _a2.height) != null ? _b2 : 0);
121
+ });
122
+ const showSub2 = Keyboard.addListener("keyboardWillShow", (event) => {
123
+ var _a2, _b2;
124
+ return setKeyboardHeight((_b2 = (_a2 = event.endCoordinates) == null ? void 0 : _a2.height) != null ? _b2 : 0);
125
+ });
126
+ const hideSub2 = Keyboard.addListener("keyboardWillHide", () => setKeyboardHeight(0));
127
+ return () => {
128
+ frameSub.remove();
129
+ showSub2.remove();
130
+ hideSub2.remove();
131
+ };
132
+ }
133
+ const showSub = Keyboard.addListener("keyboardDidShow", (event) => {
134
+ var _a2, _b2;
135
+ return setKeyboardHeight((_b2 = (_a2 = event.endCoordinates) == null ? void 0 : _a2.height) != null ? _b2 : 0);
136
+ });
137
+ const hideSub = Keyboard.addListener("keyboardDidHide", () => setKeyboardHeight(0));
138
+ return () => {
139
+ showSub.remove();
140
+ hideSub.remove();
141
+ };
142
+ }, []);
55
143
  const handleModeSwitch = useCallback((mode) => {
56
144
  setActiveMode(mode);
57
145
  }, []);
146
+ const navigateToChat = useCallback((channelId, query, mode, attachments) => {
147
+ var _a2;
148
+ const params = {
149
+ channelId,
150
+ orgName: (_a2 = effectiveOrgName != null ? effectiveOrgName : routeOrgName) != null ? _a2 : void 0,
151
+ initialQuery: query,
152
+ initialMode: mode
153
+ };
154
+ if (attachments && attachments.length > 0) {
155
+ params.initialAttachments = attachments;
156
+ }
157
+ navigation.dispatch(CommonActions.navigate({
158
+ name: "MainStack.Chat",
159
+ params
160
+ }));
161
+ }, [navigation, effectiveOrgName, routeOrgName]);
58
162
  const handleSubmit = useCallback(async (attachments) => {
59
163
  if (!canSubmit || isLoading || disabled) return;
60
164
  const submission = {
@@ -62,74 +166,97 @@ function HomeScreenContent({
62
166
  query: trimmedQuery,
63
167
  attachments
64
168
  };
65
- if (activeMode === "deep-search" && onSubmitProp) {
169
+ if (onSubmitProp) {
66
170
  onSubmitProp(submission);
67
- setValue("");
68
- return;
69
171
  }
70
- if (onSubmitProp && activeMode === "chat") {
71
- onSubmitProp(submission);
72
- setValue("");
172
+ if (!effectiveOrgName || !effectiveProjectId) {
173
+ console.warn("[HomeScreen] orgName/projectId not ready \u2014 skipping submit.");
73
174
  return;
74
175
  }
75
- if (!activeSessionId) {
76
- const newSessionId = v4();
77
- const title = activeMode === "deep-search" ? "Deep Search" : "New Chat";
78
- try {
79
- await createSession({
80
- id: newSessionId,
81
- title
82
- });
83
- setActiveSessionId(newSessionId);
84
- setValue("");
85
- sendMessage(trimmedQuery, void 0, newSessionId);
86
- } catch (err) {
87
- console.error("[HomeScreen] Failed to create session:", err);
88
- }
89
- } else {
90
- setValue("");
91
- sendMessage(trimmedQuery);
92
- }
93
- }, [canSubmit, isLoading, disabled, activeMode, trimmedQuery, activeSessionId, onSubmitProp, createSession, sendMessage]);
94
- const handleNewChat = useCallback(() => {
95
- setActiveSessionId(null);
176
+ const requestedChannelId = v4();
177
+ const title = buildChannelTitle(activeMode, requestedChannelId);
178
+ const queryToForward = trimmedQuery;
179
+ const attachmentsToForward = attachments;
96
180
  setValue("");
97
- }, []);
98
- useEffect(() => {
99
- navigation.setOptions({
100
- headerRight: () => /* @__PURE__ */ jsx(Pressable, { onPress: handleNewChat, style: ({
101
- pressed
102
- }) => [styles.newChatButton, pressed && styles.newChatButtonPressed], accessibilityLabel: "New chat", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "chat-plus-outline", size: 26, color: "#000" }) })
181
+ void createChannel({
182
+ id: requestedChannelId,
183
+ title,
184
+ isShared: false,
185
+ sharedSlug: null,
186
+ isArchived: false,
187
+ isPinned: false,
188
+ model: null,
189
+ systemPrompt: null,
190
+ orgName: effectiveOrgName,
191
+ projectId: effectiveProjectId
192
+ }).catch((err) => {
193
+ console.error("[HomeScreen] createChannel failed:", err);
103
194
  });
104
- }, [navigation, handleNewChat]);
105
- const handleSendMessage = useCallback(async (text) => {
106
- if (!text.trim() || isLoading || disabled) return;
107
- const submission = {
108
- mode: activeMode,
109
- query: text.trim()
110
- };
111
- if (activeMode === "deep-search" && onSubmitProp) {
112
- onSubmitProp(submission);
195
+ navigateToChat(requestedChannelId, queryToForward, activeMode, attachmentsToForward);
196
+ }, [canSubmit, isLoading, disabled, activeMode, trimmedQuery, onSubmitProp, effectiveOrgName, effectiveProjectId, createChannel, navigateToChat]);
197
+ const surfaceColor = isDark ? "#0f172a" : mobileTokens.color.surface;
198
+ const primaryTextColor = isDark ? "#e5e7eb" : mobileTokens.color.text;
199
+ const secondaryTextColor = isDark ? "#94a3b8" : mobileTokens.color.textMuted;
200
+ const contentMaxWidth = Math.min(720, Math.max(360, screenWidth - 24));
201
+ useEffect(() => {
202
+ var _a2, _b2, _c2;
203
+ const currentRouteOrgName = ((_b2 = (_a2 = route == null ? void 0 : route.params) == null ? void 0 : _a2.orgName) == null ? void 0 : _b2.trim()) || "";
204
+ if (currentRouteOrgName) {
205
+ syncedRouteOrgRef.current = currentRouteOrgName;
113
206
  return;
114
207
  }
115
- if (!activeSessionId) {
116
- const newSessionId = v4();
117
- const title = activeMode === "deep-search" ? "Deep Search" : "New Chat";
118
- try {
119
- await createSession({
120
- id: newSessionId,
121
- title
122
- });
123
- setActiveSessionId(newSessionId);
124
- sendMessage(text.trim(), void 0, newSessionId);
125
- } catch (err) {
126
- console.error("[HomeScreen] Failed to create session:", err);
127
- }
128
- } else {
129
- sendMessage(text.trim());
208
+ const orgToApply = resolvedOrgName;
209
+ if (!orgToApply || orgLoading) {
210
+ return;
130
211
  }
131
- }, [isLoading, disabled, activeSessionId, activeMode, onSubmitProp, createSession, sendMessage]);
132
- const leftItems = getDefaultLeftItems({
212
+ if (syncedRouteOrgRef.current === orgToApply) {
213
+ return;
214
+ }
215
+ syncedRouteOrgRef.current = orgToApply;
216
+ syncMobileOrgRouteContext(dispatch, orgToApply, {
217
+ userId: accountUserId,
218
+ routePath: mobileRoutePath
219
+ });
220
+ navigation.dispatch(CommonActions.navigate({
221
+ name: (_c2 = route == null ? void 0 : route.name) != null ? _c2 : "MainStack.Layout.Home",
222
+ params: __spreadProps(__spreadValues({}, (route == null ? void 0 : route.params) || {}), {
223
+ orgName: orgToApply
224
+ }),
225
+ merge: true
226
+ }));
227
+ }, [dispatch, navigation, route == null ? void 0 : route.name, route == null ? void 0 : route.params, (_c = route == null ? void 0 : route.params) == null ? void 0 : _c.orgName, resolvedOrgName, accountUserId, mobileRoutePath, orgLoading]);
228
+ const handleValueChange = useCallback((e) => {
229
+ setValue(e.nativeEvent.text);
230
+ }, []);
231
+ const handleMicPress = useCallback(() => {
232
+ if (hasQuery) return;
233
+ setVoiceError(null);
234
+ Keyboard.dismiss();
235
+ void (async () => {
236
+ const {
237
+ granted,
238
+ error
239
+ } = await requestMicPermission();
240
+ if (!granted) {
241
+ setVoiceError(error || "Microphone is not available.");
242
+ return;
243
+ }
244
+ setShowAudioRecorder(true);
245
+ })();
246
+ }, [hasQuery]);
247
+ const handleTranscriptionComplete = useCallback((text) => {
248
+ const cleaned = (text != null ? text : "").trim();
249
+ setShowAudioRecorder(false);
250
+ if (!cleaned) return;
251
+ setValue((prev) => prev.trim().length > 0 ? `${prev.trim()} ${cleaned}` : cleaned);
252
+ }, []);
253
+ const handleRecorderCancel = useCallback(() => {
254
+ setShowAudioRecorder(false);
255
+ }, []);
256
+ const handleRecorderError = useCallback((error) => {
257
+ setVoiceError(error);
258
+ }, []);
259
+ const leftItems = useMemo(() => getDefaultLeftItems({
133
260
  search: {
134
261
  active: activeMode === "chat",
135
262
  onClick: () => handleModeSwitch("chat")
@@ -139,10 +266,12 @@ function HomeScreenContent({
139
266
  onClick: () => handleModeSwitch("deep-search")
140
267
  },
141
268
  lightbulb: {
142
- enabled: false
269
+ onClick: () => {
270
+ console.log("build mode");
271
+ }
143
272
  }
144
- });
145
- const rightItems = getDefaultRightItems({
273
+ }), [activeMode, handleModeSwitch]);
274
+ const rightItems = useMemo(() => getDefaultRightItems({
146
275
  tag: {
147
276
  enabled: false
148
277
  },
@@ -150,75 +279,166 @@ function HomeScreenContent({
150
279
  enabled: false
151
280
  },
152
281
  camera: {
153
- onClick: () => console.log("camera")
282
+ enabled: false
154
283
  },
155
284
  image: {
156
- onClick: () => console.log("image")
285
+ enabled: false
157
286
  },
158
287
  attach: {
159
- onClick: () => console.log("attach")
288
+ enabled: false
160
289
  }
161
- });
162
- return /* @__PURE__ */ jsx(SafeAreaView, { style: {
290
+ }), []);
291
+ const inputConfig = useMemo(() => ({
292
+ value,
293
+ onChange: handleValueChange,
294
+ placeholder: inputPlaceholder,
295
+ disabled: isLoading || disabled
296
+ }), [value, handleValueChange, inputPlaceholder, isLoading, disabled]);
297
+ const micSendButton = useMemo(() => ({
298
+ hasContent: canSubmit,
299
+ onSend: () => handleSubmit(),
300
+ onMic: handleMicPress,
301
+ disabled: isLoading || disabled,
302
+ isLoading
303
+ }), [canSubmit, handleSubmit, handleMicPress, isLoading, disabled]);
304
+ return /* @__PURE__ */ jsx(SafeAreaView, { edges: ["left", "right", "bottom"], style: {
163
305
  flex: 1,
164
- backgroundColor: "#fff"
165
- }, children: /* @__PURE__ */ jsxs(Box, { flex: 1, width: "100%", children: [
166
- chatError && /* @__PURE__ */ jsx(Box, { mb: "$2", mx: "$4", p: "$3", bg: "$gray200", borderRadius: "$md", children: /* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray900", children: chatError }) }),
167
- hasMessages || response ? /* @__PURE__ */ jsx(Box, { flex: 1, width: "100%", alignSelf: "stretch", children: /* @__PURE__ */ jsx(MessagesContainerUI, { mode: "plan", showBackButton: false, onBackPress: handleNewChat, compactTop: true, messagesContainerStyle: {
168
- paddingHorizontal: 0,
169
- paddingTop: 0,
170
- margin: 0
171
- }, listContentStyle: {
172
- paddingTop: 0,
173
- margin: 0
174
- }, messages: messages.map((msg, index) => ({
175
- id: `msg-${index}-${msg.role}`,
176
- role: msg.role,
177
- content: msg.content,
178
- metadata: msg.metadata
179
- })), streamingContent: response, currentUser: {
180
- id: "user"
181
- }, onSend: handleSendMessage, disabled: isLoading || disabled, isLoading, onStop: isStreaming ? cancel : onStop, renderPlanInputToolbar: ({
182
- value: value2,
183
- onChange,
184
- onSend,
185
- disabled: inputDisabled
186
- }) => /* @__PURE__ */ jsx(InputToolBar, { inputConfig: {
187
- value: value2,
188
- onChange: (e) => onChange(e.nativeEvent.text),
189
- placeholder: inputPlaceholder,
190
- disabled: inputDisabled
191
- }, leftItems, rightItems, templateButton: null, templateModalConfig: null, micSendButton: {
192
- hasContent: value2.trim().length > 0,
193
- onSend: () => onSend(value2.trim()),
194
- onMic: () => console.log("mic"),
195
- disabled: inputDisabled,
196
- isLoading,
197
- onStop: isStreaming ? cancel : onStop
198
- } }), renderBuildInputToolbar: () => null }) }) : /* @__PURE__ */ jsx(Box, { flex: 1, justifyContent: "center", alignItems: "stretch", p: "$4", children: /* @__PURE__ */ jsx(InputToolBar, { inputConfig: {
199
- value,
200
- onChange: (e) => setValue(e.nativeEvent.text),
201
- placeholder: inputPlaceholder,
202
- disabled: isLoading || disabled
203
- }, leftItems, rightItems, templateButton: null, templateModalConfig: null, micSendButton: {
204
- hasContent: canSubmit,
205
- onSend: () => handleSubmit(),
206
- onMic: () => console.log("mic"),
207
- disabled: isLoading || disabled,
208
- isLoading,
209
- onStop
210
- } }) })
211
- ] }) });
306
+ backgroundColor: surfaceColor
307
+ }, children: /* @__PURE__ */ jsx(TouchableWithoutFeedback, { onPress: Keyboard.dismiss, accessible: false, children: /* @__PURE__ */ jsxs(Box, { flex: 1, width: "100%", position: "relative", children: [
308
+ /* @__PURE__ */ jsx(EmptyStateSection, { isDark, secondaryTextColor, primaryTextColor, activeMode, onModeSwitch: handleModeSwitch }),
309
+ /* @__PURE__ */ jsx(View, { style: [styles.bottomComposerWrap, {
310
+ bottom: Math.max(0, keyboardHeight - insets.bottom),
311
+ paddingBottom: Math.max(insets.bottom - 6, 2)
312
+ }], children: /* @__PURE__ */ jsxs(View, { style: [styles.bottomComposerInner, {
313
+ width: contentMaxWidth
314
+ }], children: [
315
+ voiceError ? /* @__PURE__ */ jsx(View, { style: [styles.voiceErrorBanner, {
316
+ backgroundColor: isDark ? "#2b1a1d" : "#fef2f2",
317
+ borderColor: isDark ? "#7f1d1d" : "#fecaca"
318
+ }], children: /* @__PURE__ */ jsx(Text, { style: [styles.voiceErrorText, {
319
+ color: isDark ? "#fecaca" : "#991b1b"
320
+ }], children: voiceError }) }) : null,
321
+ showAudioRecorder ? (
322
+ /*
323
+ * Render-time JS errors thrown by `useAudioRecorder`
324
+ * (e.g. expo-audio native module missing, recorder
325
+ * constructor throws in a release build) are caught
326
+ * by the boundary and converted into a soft cancel
327
+ * via the same handlers the panel itself uses on
328
+ * runtime errors. Without this, a throw during the
329
+ * panel's render phase kills the JS thread in
330
+ * release / TestFlight.
331
+ */
332
+ /* @__PURE__ */ jsx(MicErrorBoundary, { onCancel: handleRecorderCancel, onError: handleRecorderError, children: /* @__PURE__ */ jsx(AudioRecorderPanel, { isDark, onTranscriptionComplete: handleTranscriptionComplete, onCancel: handleRecorderCancel, onError: handleRecorderError }) })
333
+ ) : /* @__PURE__ */ jsx(InputToolBar, { inputConfig, leftItems, rightItems, templateButton: null, templateModalConfig: null, micSendButton })
334
+ ] }) })
335
+ ] }) }) });
212
336
  }
213
337
  const styles = StyleSheet.create({
214
- newChatButton: {
338
+ emptyCenterTitleWrap: {
339
+ flex: 1,
340
+ alignItems: "center",
341
+ justifyContent: "flex-start",
342
+ paddingHorizontal: 24,
343
+ paddingTop: 88,
344
+ paddingBottom: 52,
345
+ maxWidth: 520,
346
+ alignSelf: "center"
347
+ },
348
+ emptyEyebrow: {
349
+ fontSize: 12,
350
+ fontWeight: "600",
351
+ letterSpacing: 0.4,
352
+ textTransform: "uppercase",
353
+ marginBottom: 10
354
+ },
355
+ emptyCenterTitle: {
356
+ marginTop: 2,
357
+ fontSize: 30,
358
+ fontWeight: "700",
359
+ textAlign: "center",
360
+ letterSpacing: -0.5
361
+ },
362
+ emptySubtitle: {
363
+ marginTop: 12,
364
+ fontSize: 14,
365
+ lineHeight: 22,
366
+ textAlign: "center",
367
+ paddingHorizontal: 16,
368
+ maxWidth: 360
369
+ },
370
+ bottomComposerWrap: {
371
+ position: "absolute",
372
+ width: "100%",
373
+ left: 0,
374
+ right: 0,
375
+ bottom: 0,
376
+ alignItems: "center",
377
+ justifyContent: "flex-end",
378
+ shadowColor: "#0f172a",
379
+ shadowOpacity: 0.08,
380
+ shadowRadius: 8,
381
+ shadowOffset: {
382
+ width: 0,
383
+ height: -2
384
+ },
385
+ backgroundColor: "transparent",
386
+ elevation: 6
387
+ },
388
+ bottomComposerInner: {
389
+ paddingHorizontal: 14,
390
+ paddingTop: 10,
391
+ paddingBottom: 4
392
+ },
393
+ voiceErrorBanner: {
394
+ marginBottom: 8,
395
+ paddingHorizontal: 12,
396
+ paddingVertical: 8,
397
+ borderRadius: 10,
398
+ borderWidth: 1
399
+ },
400
+ voiceErrorText: {
401
+ fontSize: 12,
402
+ fontWeight: "500"
403
+ },
404
+ emptyModePillRow: {
405
+ flexDirection: "row",
406
+ alignItems: "center",
407
+ gap: 8,
408
+ marginBottom: 22,
409
+ borderRadius: 16,
215
410
  padding: 6,
216
- marginRight: 4,
411
+ borderWidth: 1,
412
+ shadowColor: "#312e81",
413
+ shadowOpacity: 0.08,
414
+ shadowRadius: 8,
415
+ shadowOffset: {
416
+ width: 0,
417
+ height: 3
418
+ },
419
+ elevation: 3
420
+ },
421
+ emptyModePill: {
422
+ flexDirection: "row",
217
423
  alignItems: "center",
218
- justifyContent: "center"
424
+ gap: 4,
425
+ paddingHorizontal: 12,
426
+ paddingVertical: 7,
427
+ borderRadius: 11
428
+ },
429
+ emptyModePillActive: {
430
+ shadowColor: "#312e81",
431
+ shadowOpacity: 0.18,
432
+ shadowRadius: 6,
433
+ shadowOffset: {
434
+ width: 0,
435
+ height: 2
436
+ },
437
+ elevation: 2
219
438
  },
220
- newChatButtonPressed: {
221
- opacity: 0.6
439
+ emptyModePillLabel: {
440
+ fontSize: 12,
441
+ fontWeight: "600"
222
442
  }
223
443
  });
224
444
  const HomeScreen = (props) => /* @__PURE__ */ jsx(HomeScreenContent, __spreadValues({}, props));export{HomeScreen as default};//# sourceMappingURL=HomeScreen.js.map