@adminide-stack/yantra-mobile 12.0.28-alpha.7 → 12.0.28-alpha.71

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