@adminide-stack/yantra-mobile 12.0.28-alpha.67 → 12.0.28-alpha.69

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 (37) hide show
  1. package/lib/api/stt.js +54 -0
  2. package/lib/api/stt.js.map +1 -0
  3. package/lib/components/GatewayConnector/GatewayConnector.js +18 -0
  4. package/lib/components/GatewayConnector/GatewayConnector.js.map +1 -0
  5. package/lib/components/NavigationHeader/NavigationHeader.js +214 -0
  6. package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -0
  7. package/lib/components/ThinkingIndicator.js +55 -0
  8. package/lib/components/ThinkingIndicator.js.map +1 -0
  9. package/lib/compute.js +108 -31
  10. package/lib/compute.js.map +1 -1
  11. package/lib/contexts/CdecliConnectionContext.js +47 -0
  12. package/lib/contexts/CdecliConnectionContext.js.map +1 -0
  13. package/lib/contexts/GatewayContext.js +1 -1
  14. package/lib/features/audio-input/AudioRecorderPanel.js +231 -0
  15. package/lib/features/audio-input/AudioRecorderPanel.js.map +1 -0
  16. package/lib/features/audio-input/MicErrorBoundary.js +34 -0
  17. package/lib/features/audio-input/MicErrorBoundary.js.map +1 -0
  18. package/lib/hooks/useCdecliAutoConnect.js +41 -18
  19. package/lib/hooks/useCdecliAutoConnect.js.map +1 -1
  20. package/lib/hooks/useChatApi.js +158 -41
  21. package/lib/hooks/useChatApi.js.map +1 -1
  22. package/lib/hooks/useChatStream.js +59 -16
  23. package/lib/hooks/useChatStream.js.map +1 -1
  24. package/lib/hooks/usePrerequisiteIds.js +8 -12
  25. package/lib/hooks/usePrerequisiteIds.js.map +1 -1
  26. package/lib/index.js +1 -1
  27. package/lib/index.js.map +1 -1
  28. package/lib/routes.json +112 -0
  29. package/lib/screens/Chat/index.js +423 -0
  30. package/lib/screens/Chat/index.js.map +1 -0
  31. package/lib/screens/ChatHistory/index.js +56 -0
  32. package/lib/screens/ChatHistory/index.js.map +1 -0
  33. package/lib/screens/Home/HomeScreen.js +136 -427
  34. package/lib/screens/Home/HomeScreen.js.map +1 -1
  35. package/lib/screens/Home/components/ChatHistoryLanding.js +436 -214
  36. package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -1
  37. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
- import {jsx,jsxs}from'react/jsx-runtime';import React,{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 {MessagesContainerUI}from'@messenger-box/platform-mobile';import {v4}from'uuid';import {ContributionSchemaId}from'common';import {useGetContextDataQuery,useGetPageSettingsQuery}from'common/graphql';import {useGatewayContext}from'../../contexts/GatewayContext.js';import {GatewayToolbarButtonMobile}from'../../components/GatewayToolbarButtonMobile.js';import {useCdecliAutoConnect}from'../../hooks/useCdecliAutoConnect.js';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {useChatMutations,useChatSessions}from'../../hooks/useChatApi.js';import {useChatStream}from'../../hooks/useChatStream.js';import DeepSearchModal from'./components/DeepSearchModal.js';import ChatHistoryLanding from'./components/ChatHistoryLanding.js';import {normalizeSummaryText,extractDeepSearchSources}from'./deepSearchUtils.js';import {YantraBrandLoader,YANTRA_LOADER_SIZE_COMPACT}from'../../components/YantraBrandLoader.js';import {mobileTokens}from'../../theme/mobileTokens.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,8 +14,9 @@ var __spreadValues = (a, b) => {
14
14
  }
15
15
  return a;
16
16
  };
17
- const SENDING_LOADER_COMPOSER_RESERVE_PX = 156;
18
- const COMPOSER_SCROLL_RESERVE_PX = 164;
17
+ function buildChannelTitle(mode, channelId) {
18
+ return mode === "deep-search" ? `deep-search-${channelId}` : `chat-channel-${channelId}`;
19
+ }
19
20
  function organizationFromSettingsValue(settings) {
20
21
  if (settings == null) return null;
21
22
  if (typeof settings === "string") {
@@ -50,44 +51,6 @@ function projectFromSettingsValue(settings) {
50
51
  }
51
52
  return null;
52
53
  }
53
- const ChatContentSection = React.memo(function ChatContentSection2({
54
- contentMaxWidth,
55
- composerScrollBottomPadding,
56
- messages,
57
- response,
58
- isLoading,
59
- disabled,
60
- isStreaming,
61
- onStop,
62
- cancel,
63
- onSend,
64
- onBackPress
65
- }) {
66
- return /* @__PURE__ */ jsx(Box, { flex: 1, width: "100%", alignSelf: "stretch", children: /* @__PURE__ */ jsx(MessagesContainerUI, { mode: "chat", showBackButton: false, onBackPress, compactTop: true, messagesContainerStyle: {
67
- paddingHorizontal: 0,
68
- paddingTop: 0,
69
- paddingBottom: composerScrollBottomPadding,
70
- margin: 0,
71
- marginTop: 0,
72
- alignSelf: "center",
73
- width: contentMaxWidth
74
- }, listContentStyle: {
75
- paddingTop: 0,
76
- paddingBottom: composerScrollBottomPadding,
77
- margin: 0,
78
- marginTop: 0,
79
- width: contentMaxWidth,
80
- alignSelf: "center",
81
- justifyContent: "flex-end"
82
- }, messages: messages.map((msg, index) => ({
83
- id: `msg-${index}-${msg.role}`,
84
- role: msg.role,
85
- content: msg.content,
86
- metadata: msg.metadata
87
- })), streamingContent: response, currentUser: {
88
- id: "user"
89
- }, onSend, disabled: isLoading || disabled, isLoading, onStop: isStreaming ? cancel : onStop, renderPlanInputToolbar: () => null, renderBuildInputToolbar: () => null }) });
90
- });
91
54
  const EmptyStateSection = React.memo(function EmptyStateSection2({
92
55
  isDark,
93
56
  secondaryTextColor,
@@ -118,6 +81,14 @@ const EmptyStateSection = React.memo(function EmptyStateSection2({
118
81
  /* @__PURE__ */ jsx(Text, { style: [styles.emptyModePillLabel, {
119
82
  color: activeMode === "deep-search" ? "#ffffff" : secondaryTextColor
120
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" })
121
92
  ] })
122
93
  ] }),
123
94
  /* @__PURE__ */ jsx(Text, { style: [styles.emptyCenterTitle, {
@@ -125,48 +96,16 @@ const EmptyStateSection = React.memo(function EmptyStateSection2({
125
96
  }], children: "How do you want to start?" }),
126
97
  /* @__PURE__ */ jsx(Text, { style: [styles.emptySubtitle, {
127
98
  color: secondaryTextColor
128
- }], children: "Use Chat for quick help, or Deep Search for researched, source-backed answers." })
99
+ }], children: "Use Chat for quick help, Deep Search for source-backed answers, or Build to assemble workflows." })
129
100
  ] }) });
130
101
  });
131
- const HeaderBackButton = React.memo(function HeaderBackButton2({
132
- color,
133
- onPress
134
- }) {
135
- return /* @__PURE__ */ jsx(Pressable, { onPress, style: ({
136
- pressed
137
- }) => [styles.backButton, pressed && styles.newChatButtonPressed], accessibilityLabel: "Back to chat", children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "chevron-left", size: 24, color }) });
138
- });
139
- const HeaderRightActions = React.memo(function HeaderRightActions2({
140
- gatewayToolbarStatus,
141
- gatewayToolbarError,
142
- onToggleGateway,
143
- gatewayToolbarLabel,
144
- gatewayToolbarTone,
145
- showChatHistory,
146
- onOpenChatHistory,
147
- onNewChat,
148
- isDark,
149
- accentColor,
150
- newChatIconColor
151
- }) {
152
- return /* @__PURE__ */ jsxs(View, { style: styles.headerRight, children: [
153
- /* @__PURE__ */ jsx(GatewayToolbarButtonMobile, { gatewayStatus: gatewayToolbarStatus, gatewayError: gatewayToolbarError, onToggleGateway, disabled: false, statusLabel: gatewayToolbarLabel, tone: gatewayToolbarTone }),
154
- !showChatHistory ? /* @__PURE__ */ jsx(Pressable, { onPress: onOpenChatHistory, style: ({
155
- pressed
156
- }) => [styles.historyHeaderButton, pressed && styles.historyHeaderButtonPressed], accessibilityLabel: "Chat history", accessibilityRole: "button", children: /* @__PURE__ */ jsx(View, { style: [styles.historyHeaderButtonInner, isDark ? styles.historyHeaderButtonInnerDark : null], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "history", size: 19, color: accentColor }) }) }) : null,
157
- /* @__PURE__ */ jsx(Pressable, { onPress: onNewChat, style: ({
158
- pressed
159
- }) => [styles.newChatButton, pressed && styles.newChatButtonPressed], accessibilityLabel: "New chat", children: /* @__PURE__ */ jsx(View, { style: [styles.newChatButtonInner, isDark ? styles.newChatButtonInnerDark : null], children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "chat-plus-outline", size: 20, color: newChatIconColor }) }) })
160
- ] });
161
- });
162
102
  function HomeScreenContent({
163
103
  initialMode = "chat",
164
104
  onSubmit: onSubmitProp,
165
- onStop,
166
105
  isLoading: isLoadingProp = false,
167
106
  disabled = false
168
107
  }) {
169
- var _a, _b, _c, _d, _e, _f, _g;
108
+ var _a, _b, _c, _d, _e;
170
109
  const {
171
110
  width: screenWidth
172
111
  } = useWindowDimensions();
@@ -174,22 +113,14 @@ function HomeScreenContent({
174
113
  const isDark = colorScheme === "dark";
175
114
  const navigation = useNavigation();
176
115
  const route = useRoute();
177
- const hasRehydratedOrgRef = React.useRef(false);
116
+ const hasRehydratedOrgRef = useRef(false);
178
117
  const [value, setValue] = useState("");
179
118
  const [activeMode, setActiveMode] = useState(initialMode);
180
- const [activeSessionId, setActiveSessionId] = useState(null);
181
- const [isDeepSearchModalOpen, setIsDeepSearchModalOpen] = useState(false);
182
- const [deepSearchQuery, setDeepSearchQuery] = useState(null);
183
- const [deepSearchSummary, setDeepSearchSummary] = useState("");
184
- const [deepSearchSources, setDeepSearchSources] = useState([]);
185
- const [researchProcessOpen, setResearchProcessOpen] = useState(true);
186
- const [sourcesAccordionOpen, setSourcesAccordionOpen] = useState(true);
187
- const [showChatHistory, setShowChatHistory] = useState(false);
188
- const [channelBootstrap, setChannelBootstrap] = useState(false);
119
+ const [showAudioRecorder, setShowAudioRecorder] = useState(false);
120
+ const [voiceError, setVoiceError] = useState(null);
189
121
  const {
190
122
  createChannel
191
123
  } = useChatMutations();
192
- useChatSessions();
193
124
  const {
194
125
  orgName: resolvedOrgName,
195
126
  projectId
@@ -223,46 +154,12 @@ function HomeScreenContent({
223
154
  const routeOrgName = ((_c = (_b = route == null ? void 0 : route.params) == null ? void 0 : _b.orgName) != null ? _c : "").trim() || null;
224
155
  const effectiveOrgName = resolvedOrgName || fallbackOrgNameFromSettings || routeOrgName || null;
225
156
  const effectiveProjectId = projectId || fallbackProjectIdFromSettings || null;
226
- const {
227
- selectedGateway
228
- } = useGatewayContext();
229
- const cdecliSelected = (selectedGateway == null ? void 0 : selectedGateway.channelType) === "cdecli-serve";
230
- const cdecli = useCdecliAutoConnect(cdecliSelected, activeSessionId != null ? activeSessionId : void 0);
231
- const cdecliConnected = cdecliSelected && cdecli.channelConnected;
232
- const effectivePersistenceMode = (_e = (_d = cdecli.persistenceMode) != null ? _d : selectedGateway == null ? void 0 : selectedGateway.persistenceMode) != null ? _e : "frontend";
233
- const chatRouting = useMemo(() => cdecliConnected ? {
234
- kind: "cdecli",
235
- channelConnected: cdecli.channelConnected,
236
- accountId: cdecli.accountId,
237
- persistenceMode: effectivePersistenceMode
238
- } : {
239
- kind: "groq"
240
- }, [cdecliConnected, cdecli.channelConnected, cdecli.accountId, effectivePersistenceMode]);
241
- const chat = useChatStream(activeSessionId, chatRouting);
242
- const {
243
- messages,
244
- response,
245
- error: chatError,
246
- isLoading: chatLoading,
247
- isStreaming,
248
- sendMessage,
249
- cancel,
250
- clearMessages
251
- } = chat;
252
157
  const trimmedQuery = value.trim();
253
158
  const hasQuery = trimmedQuery.length > 0;
254
159
  const canSubmit = hasQuery && Boolean(routeOrgName || effectiveOrgName);
255
- const isLoading = isLoadingProp || chatLoading;
160
+ const isLoading = isLoadingProp;
256
161
  const isResearchMode = activeMode === "deep-search";
257
162
  const inputPlaceholder = !effectiveOrgName ? "Initializing workspace..." : isResearchMode ? "Research anything..." : "Ask anything...";
258
- const waitingForAssistant = useMemo(() => {
259
- var _a2;
260
- if (!chatLoading && !isStreaming || messages.length === 0) return false;
261
- return ((_a2 = messages[messages.length - 1]) == null ? void 0 : _a2.role) === "user";
262
- }, [chatLoading, isStreaming, messages]);
263
- const pinSendingLoaderNearComposer = useMemo(() => messages.length > 0 || Boolean((response != null ? response : "").trim()), [messages.length, response]);
264
- const showSendingLoader = !showChatHistory && (channelBootstrap || waitingForAssistant);
265
- const hasRenderableConversation = messages.length > 0 || isStreaming;
266
163
  const insets = useSafeAreaInsets();
267
164
  const [keyboardHeight, setKeyboardHeight] = useState(0);
268
165
  useEffect(() => {
@@ -295,14 +192,42 @@ function HomeScreenContent({
295
192
  const handleModeSwitch = useCallback((mode) => {
296
193
  setActiveMode(mode);
297
194
  }, []);
298
- const ensureSessionId = useCallback(async (mode) => {
299
- if (activeSessionId) return activeSessionId;
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]);
211
+ const handleSubmit = useCallback(async (attachments) => {
212
+ if (!canSubmit || isLoading || disabled) return;
213
+ const submission = {
214
+ mode: activeMode,
215
+ query: trimmedQuery,
216
+ attachments
217
+ };
218
+ if (onSubmitProp) {
219
+ onSubmitProp(submission);
220
+ }
300
221
  if (!effectiveOrgName || !effectiveProjectId) {
301
- throw new Error("Workspace is still initializing. Please retry in a moment.");
222
+ console.warn("[HomeScreen] orgName/projectId not ready \u2014 skipping submit.");
223
+ return;
302
224
  }
303
225
  const requestedChannelId = v4();
304
- const title = mode === "deep-search" ? `deep-search-${requestedChannelId}` : `chat-channel-${requestedChannelId}`;
305
- const session = await createChannel({
226
+ const title = buildChannelTitle(activeMode, requestedChannelId);
227
+ const queryToForward = trimmedQuery;
228
+ const attachmentsToForward = attachments;
229
+ setValue("");
230
+ void createChannel({
306
231
  id: requestedChannelId,
307
232
  title,
308
233
  isShared: false,
@@ -313,76 +238,14 @@ function HomeScreenContent({
313
238
  systemPrompt: null,
314
239
  orgName: effectiveOrgName,
315
240
  projectId: effectiveProjectId
241
+ }).catch((err) => {
242
+ console.error("[HomeScreen] createChannel failed:", err);
316
243
  });
317
- setActiveSessionId(session.id);
318
- return session.id;
319
- }, [activeSessionId, createChannel, effectiveOrgName, effectiveProjectId]);
320
- const handleSubmit = useCallback(async (attachments) => {
321
- if (!canSubmit || isLoading || disabled) return;
322
- const submission = {
323
- mode: activeMode,
324
- query: trimmedQuery,
325
- attachments
326
- };
327
- if (activeMode === "deep-search") {
328
- if (onSubmitProp) {
329
- onSubmitProp(submission);
330
- }
331
- setValue("");
332
- setDeepSearchQuery(trimmedQuery);
333
- setDeepSearchSummary("");
334
- setDeepSearchSources([]);
335
- setIsDeepSearchModalOpen(true);
336
- try {
337
- setChannelBootstrap(true);
338
- const sessionId = await ensureSessionId("deep-search");
339
- await sendMessage(trimmedQuery, void 0, sessionId);
340
- } catch (err) {
341
- console.error("[HomeScreen] Failed to create deep-search session:", err);
342
- } finally {
343
- setChannelBootstrap(false);
344
- }
345
- return;
346
- }
347
- if (onSubmitProp && activeMode === "chat") {
348
- onSubmitProp(submission);
349
- setValue("");
350
- return;
351
- }
352
- try {
353
- setChannelBootstrap(true);
354
- const sessionId = await ensureSessionId("chat");
355
- setValue("");
356
- await sendMessage(trimmedQuery, void 0, sessionId);
357
- } catch (err) {
358
- console.error("[HomeScreen] Failed to create session:", err);
359
- } finally {
360
- setChannelBootstrap(false);
361
- }
362
- }, [canSubmit, isLoading, disabled, activeMode, trimmedQuery, activeSessionId, onSubmitProp, ensureSessionId, sendMessage]);
363
- const handleNewChat = useCallback(() => {
364
- setShowChatHistory(false);
365
- setActiveSessionId(null);
366
- setValue("");
367
- clearMessages();
368
- }, [clearMessages]);
369
- const handleOpenChatHistory = useCallback(() => {
370
- setShowChatHistory(true);
371
- }, []);
372
- const handleCloseChatHistory = useCallback(() => {
373
- setShowChatHistory(false);
374
- }, []);
375
- const handleToggleGateway = useCallback(() => {
376
- }, []);
377
- const gatewayToolbarStatus = cdecli.status === "connecting" ? "connecting" : cdecli.status === "connected" ? "connected" : cdecli.status === "error" ? "error" : "disconnected";
378
- const gatewayToolbarTone = "default";
379
- const gatewayToolbarLabel = cdecli.status === "connecting" ? "Checking..." : void 0;
380
- const gatewayToolbarError = cdecli.error;
244
+ navigateToChat(requestedChannelId, queryToForward, activeMode, attachmentsToForward);
245
+ }, [canSubmit, isLoading, disabled, activeMode, trimmedQuery, onSubmitProp, effectiveOrgName, effectiveProjectId, createChannel, navigateToChat]);
381
246
  const surfaceColor = isDark ? "#0f172a" : mobileTokens.color.surface;
382
247
  const primaryTextColor = isDark ? "#e5e7eb" : mobileTokens.color.text;
383
248
  const secondaryTextColor = isDark ? "#94a3b8" : mobileTokens.color.textMuted;
384
- const accentColor = isDark ? "#a5b4fc" : "#4338ca";
385
- const newChatIconColor = isDark ? "#e5e7eb" : "#000000";
386
249
  const contentMaxWidth = Math.min(720, Math.max(360, screenWidth - 24));
387
250
  useEffect(() => {
388
251
  var _a2, _b2, _c2;
@@ -391,7 +254,7 @@ function HomeScreenContent({
391
254
  (_c2 = navigation.setParams) == null ? void 0 : _c2.call(navigation, {
392
255
  orgName: effectiveOrgName
393
256
  });
394
- }, [navigation, (_f = route == null ? void 0 : route.params) == null ? void 0 : _f.orgName, effectiveOrgName]);
257
+ }, [navigation, (_d = route == null ? void 0 : route.params) == null ? void 0 : _d.orgName, effectiveOrgName]);
395
258
  useEffect(() => {
396
259
  var _a2, _b2, _c2;
397
260
  const currentOrgName = ((_b2 = (_a2 = route == null ? void 0 : route.params) == null ? void 0 : _a2.orgName) == null ? void 0 : _b2.trim()) || "";
@@ -405,116 +268,47 @@ function HomeScreenContent({
405
268
  merge: true,
406
269
  key: Date.now().toString()
407
270
  }));
408
- }, [navigation, (_g = route == null ? void 0 : route.params) == null ? void 0 : _g.orgName, effectiveOrgName]);
409
- useEffect(() => {
410
- const headerLeft = showChatHistory ? () => /* @__PURE__ */ jsx(HeaderBackButton, { color: primaryTextColor, onPress: handleCloseChatHistory }) : void 0;
411
- const headerRight = () => /* @__PURE__ */ jsx(HeaderRightActions, { gatewayToolbarStatus, gatewayToolbarError, onToggleGateway: handleToggleGateway, gatewayToolbarLabel, gatewayToolbarTone, showChatHistory, onOpenChatHistory: handleOpenChatHistory, onNewChat: handleNewChat, isDark, accentColor, newChatIconColor });
412
- navigation.setOptions({
413
- drawerLabel: "Chat",
414
- headerTitle: showChatHistory ? "Chats" : "Yantra",
415
- headerLeft,
416
- headerRight
417
- });
418
- }, [navigation, showChatHistory, handleCloseChatHistory, handleOpenChatHistory, handleNewChat, handleToggleGateway, gatewayToolbarStatus, gatewayToolbarError, gatewayToolbarLabel, gatewayToolbarTone, primaryTextColor, accentColor, newChatIconColor, isDark]);
419
- const handleSendMessage = useCallback(async (text) => {
420
- if (!text.trim() || isLoading || disabled) return;
421
- const submission = {
422
- mode: activeMode,
423
- query: text.trim()
424
- };
425
- if (activeMode === "deep-search") {
426
- if (onSubmitProp) {
427
- onSubmitProp(submission);
428
- }
429
- setDeepSearchQuery(text.trim());
430
- setDeepSearchSummary("");
431
- setDeepSearchSources([]);
432
- setIsDeepSearchModalOpen(true);
433
- try {
434
- setChannelBootstrap(true);
435
- const sessionId = await ensureSessionId("deep-search");
436
- await sendMessage(text.trim(), void 0, sessionId);
437
- } catch (err) {
438
- console.error("[HomeScreen] Failed to create deep-search session:", err);
439
- } finally {
440
- setChannelBootstrap(false);
441
- }
442
- return;
443
- }
444
- try {
445
- setChannelBootstrap(true);
446
- const sessionId = await ensureSessionId("chat");
447
- await sendMessage(text.trim(), void 0, sessionId);
448
- } catch (err) {
449
- console.error("[HomeScreen] Failed to create session:", err);
450
- } finally {
451
- setChannelBootstrap(false);
452
- }
453
- }, [isLoading, disabled, activeMode, onSubmitProp, ensureSessionId, sendMessage]);
454
- const latestAssistantMessage = useMemo(() => {
455
- var _a2, _b2, _c2;
456
- for (let i = messages.length - 1; i >= 0; i -= 1) {
457
- if (((_a2 = messages[i]) == null ? void 0 : _a2.role) === "assistant") return (_c2 = (_b2 = messages[i]) == null ? void 0 : _b2.content) != null ? _c2 : "";
458
- }
459
- return "";
460
- }, [messages]);
461
- const deepSearchPreviewContent = response || deepSearchSummary;
462
- const deepSearchPreviewNormalized = useMemo(() => normalizeSummaryText(deepSearchPreviewContent || deepSearchSummary || ""), [deepSearchPreviewContent, deepSearchSummary]);
463
- const handleDeepSearchClose = useCallback(() => {
464
- if (isStreaming) {
465
- cancel();
466
- }
467
- setIsDeepSearchModalOpen(false);
468
- setDeepSearchQuery(null);
469
- setDeepSearchSummary("");
470
- setDeepSearchSources([]);
471
- setResearchProcessOpen(true);
472
- setSourcesAccordionOpen(true);
473
- }, [isStreaming, cancel]);
474
- const handleRetryDeepSearch = useCallback(async () => {
475
- if (!deepSearchQuery || isStreaming) return;
476
- try {
477
- setChannelBootstrap(true);
478
- const sessionId = await ensureSessionId("deep-search");
479
- await sendMessage(deepSearchQuery, void 0, sessionId);
480
- } catch (error) {
481
- console.error("[HomeScreen] Failed to retry deep-search:", error);
482
- } finally {
483
- setChannelBootstrap(false);
484
- }
485
- }, [deepSearchQuery, isStreaming, ensureSessionId, sendMessage]);
271
+ }, [navigation, (_e = route == null ? void 0 : route.params) == null ? void 0 : _e.orgName, effectiveOrgName]);
486
272
  const handleValueChange = useCallback((e) => {
487
273
  setValue(e.nativeEvent.text);
488
274
  }, []);
489
275
  const handleMicPress = useCallback(() => {
490
- console.log("mic");
491
- }, []);
492
- const handleSelectHistorySession = useCallback((channelId) => {
493
- setShowChatHistory(false);
494
- setActiveSessionId(channelId);
495
- setActiveMode("chat");
276
+ if (hasQuery) return;
277
+ setVoiceError(null);
278
+ Keyboard.dismiss();
279
+ void (async () => {
280
+ try {
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);
294
+ } catch (err) {
295
+ const msg = err instanceof Error ? err.message : String(err);
296
+ setVoiceError(`Could not start voice input: ${msg}`);
297
+ }
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);
496
305
  }, []);
497
- const handleComposeFromHistory = useCallback(() => {
498
- setShowChatHistory(false);
499
- setActiveSessionId(null);
500
- setValue("");
501
- clearMessages();
502
- }, [clearMessages]);
503
- const handleToggleResearchProcess = useCallback(() => {
504
- setResearchProcessOpen((prev) => !prev);
306
+ const handleRecorderCancel = useCallback(() => {
307
+ setShowAudioRecorder(false);
505
308
  }, []);
506
- const handleToggleSourcesAccordion = useCallback(() => {
507
- setSourcesAccordionOpen((prev) => !prev);
309
+ const handleRecorderError = useCallback((error) => {
310
+ setVoiceError(error);
508
311
  }, []);
509
- const handleRetryDeepSearchPress = useCallback(() => {
510
- void handleRetryDeepSearch();
511
- }, [handleRetryDeepSearch]);
512
- useEffect(() => {
513
- if (!deepSearchQuery || isStreaming || !latestAssistantMessage) return;
514
- setDeepSearchSummary(normalizeSummaryText(latestAssistantMessage));
515
- setDeepSearchSources(extractDeepSearchSources(latestAssistantMessage));
516
- }, [deepSearchQuery, isStreaming, latestAssistantMessage]);
517
- const composerScrollBottomPadding = COMPOSER_SCROLL_RESERVE_PX;
518
312
  const leftItems = useMemo(() => getDefaultLeftItems({
519
313
  search: {
520
314
  active: activeMode === "chat",
@@ -525,7 +319,9 @@ function HomeScreenContent({
525
319
  onClick: () => handleModeSwitch("deep-search")
526
320
  },
527
321
  lightbulb: {
528
- enabled: false
322
+ onClick: () => {
323
+ console.log("build mode");
324
+ }
529
325
  }
530
326
  }), [activeMode, handleModeSwitch]);
531
327
  const rightItems = useMemo(() => getDefaultRightItems({
@@ -536,16 +332,13 @@ function HomeScreenContent({
536
332
  enabled: false
537
333
  },
538
334
  camera: {
539
- enabled: false,
540
- onClick: () => console.log("camera")
335
+ enabled: false
541
336
  },
542
337
  image: {
543
- enabled: false,
544
- onClick: () => console.log("image")
338
+ enabled: false
545
339
  },
546
340
  attach: {
547
- enabled: false,
548
- onClick: () => console.log("attach")
341
+ enabled: false
549
342
  }
550
343
  }), []);
551
344
  const inputConfig = useMemo(() => ({
@@ -559,136 +352,42 @@ function HomeScreenContent({
559
352
  onSend: () => handleSubmit(),
560
353
  onMic: handleMicPress,
561
354
  disabled: isLoading || disabled,
562
- isLoading,
563
- onStop: isStreaming ? cancel : onStop
564
- }), [canSubmit, handleSubmit, handleMicPress, isLoading, disabled, isStreaming, cancel, onStop]);
565
- return /* @__PURE__ */ jsxs(SafeAreaView, { edges: ["left", "right", "bottom"], style: {
355
+ isLoading
356
+ }), [canSubmit, handleSubmit, handleMicPress, isLoading, disabled]);
357
+ return /* @__PURE__ */ jsx(SafeAreaView, { edges: ["left", "right", "bottom"], style: {
566
358
  flex: 1,
567
359
  backgroundColor: surfaceColor
568
- }, children: [
569
- /* @__PURE__ */ jsx(TouchableWithoutFeedback, { onPress: Keyboard.dismiss, accessible: false, children: /* @__PURE__ */ jsxs(Box, { flex: 1, width: "100%", position: "relative", children: [
570
- (chatError || cdecli.error) && /* @__PURE__ */ jsx(Box, { mb: "$2", mx: "$4", p: "$3", borderRadius: "$md", style: {
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, {
571
369
  backgroundColor: isDark ? "#2b1a1d" : "#fef2f2",
572
- borderWidth: 1,
573
370
  borderColor: isDark ? "#7f1d1d" : "#fecaca"
574
- }, children: /* @__PURE__ */ jsx(Text, { fontSize: "$sm", style: {
371
+ }], children: /* @__PURE__ */ jsx(Text, { style: [styles.voiceErrorText, {
575
372
  color: isDark ? "#fecaca" : "#991b1b"
576
- }, children: chatError || cdecli.error }) }),
577
- showChatHistory ? /* @__PURE__ */ jsx(ChatHistoryLanding, { onSelectSession: handleSelectHistorySession, onCompose: handleComposeFromHistory }) : hasRenderableConversation ? /* @__PURE__ */ jsx(ChatContentSection, { contentMaxWidth, composerScrollBottomPadding, messages, response, isLoading, disabled, isStreaming, onStop, cancel, onSend: handleSendMessage, onBackPress: handleNewChat }) : /* @__PURE__ */ jsx(EmptyStateSection, { isDark, secondaryTextColor, primaryTextColor, activeMode, onModeSwitch: handleModeSwitch }),
578
- !showChatHistory ? /* @__PURE__ */ jsx(View, { style: [styles.bottomComposerWrap, {
579
- bottom: Math.max(0, keyboardHeight - insets.bottom),
580
- paddingBottom: Math.max(insets.bottom - 6, 2)
581
- // backgroundColor: composerBarBackground,
582
- // borderTopColor: composerBarBorder,
583
- }], children: /* @__PURE__ */ jsx(View, { style: [styles.bottomComposerInner, {
584
- width: contentMaxWidth
585
- }], children: /* @__PURE__ */ jsx(InputToolBar, { inputConfig, leftItems, rightItems, templateButton: null, templateModalConfig: null, micSendButton }) }) }) : null,
586
- showSendingLoader ? /* @__PURE__ */ jsx(View, { pointerEvents: "none", style: pinSendingLoaderNearComposer ? [styles.sendingLoaderAboveComposer, {
587
- bottom: Math.max(insets.bottom, 12) + SENDING_LOADER_COMPOSER_RESERVE_PX
588
- }] : styles.sendingLoaderEmptyState, children: /* @__PURE__ */ jsx(YantraBrandLoader, { size: YANTRA_LOADER_SIZE_COMPACT }) }) : null
589
- ] }) }),
590
- /* @__PURE__ */ jsx(DeepSearchModal, { visible: isDeepSearchModalOpen, query: deepSearchQuery, summaryText: deepSearchPreviewNormalized, sources: deepSearchSources, isStreaming, researchProcessOpen, sourcesAccordionOpen, onToggleResearchProcess: handleToggleResearchProcess, onToggleSourcesAccordion: handleToggleSourcesAccordion, onRetry: handleRetryDeepSearchPress, onStop: cancel, onClose: handleDeepSearchClose })
591
- ] });
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
+ ] }) }) });
592
389
  }
593
390
  const styles = StyleSheet.create({
594
- /** First message / empty screen: loader in the middle of the pane. */
595
- sendingLoaderEmptyState: {
596
- position: "absolute",
597
- left: 0,
598
- right: 0,
599
- top: 0,
600
- bottom: 0,
601
- justifyContent: "center",
602
- alignItems: "center",
603
- zIndex: 40
604
- },
605
- /** Active thread: loader just above the input, not over message history. */
606
- sendingLoaderAboveComposer: {
607
- position: "absolute",
608
- left: 0,
609
- right: 0,
610
- alignItems: "center",
611
- justifyContent: "flex-end",
612
- paddingBottom: 8,
613
- zIndex: 40
614
- },
615
- headerRight: {
616
- flexDirection: "row",
617
- alignItems: "center",
618
- marginRight: 6,
619
- gap: 6
620
- },
621
- historyHeaderButton: {
622
- marginHorizontal: 0,
623
- padding: 0,
624
- borderRadius: 22
625
- },
626
- historyHeaderButtonPressed: {
627
- opacity: 0.72
628
- },
629
- historyHeaderButtonInner: {
630
- width: 32,
631
- height: 32,
632
- borderRadius: 16,
633
- alignItems: "center",
634
- justifyContent: "center",
635
- backgroundColor: mobileTokens.color.primarySoft,
636
- borderWidth: StyleSheet.hairlineWidth,
637
- borderColor: mobileTokens.color.primaryBorder,
638
- shadowColor: "#312e81",
639
- shadowOpacity: 0.1,
640
- shadowRadius: 5,
641
- shadowOffset: {
642
- width: 0,
643
- height: 2
644
- },
645
- elevation: 2
646
- },
647
- historyHeaderButtonInnerDark: {
648
- backgroundColor: "#1e293b",
649
- borderColor: "rgba(148, 163, 184, 0.35)",
650
- shadowColor: "#111827"
651
- },
652
- newChatButton: {
653
- padding: 0,
654
- alignItems: "center",
655
- justifyContent: "center",
656
- borderRadius: 22
657
- },
658
- newChatButtonInner: {
659
- width: 32,
660
- height: 32,
661
- borderRadius: 16,
662
- alignItems: "center",
663
- justifyContent: "center",
664
- backgroundColor: mobileTokens.color.surface,
665
- borderWidth: 1,
666
- borderColor: mobileTokens.color.border,
667
- shadowColor: "#0f172a",
668
- shadowOpacity: 0.08,
669
- shadowRadius: 5,
670
- shadowOffset: {
671
- width: 0,
672
- height: 2
673
- },
674
- elevation: 2
675
- },
676
- newChatButtonInnerDark: {
677
- backgroundColor: "#0f172a",
678
- borderColor: "#334155"
679
- },
680
- backButton: {
681
- marginLeft: 6,
682
- width: 36,
683
- height: 36,
684
- borderRadius: 18,
685
- alignItems: "center",
686
- justifyContent: "center",
687
- backgroundColor: "#f3f4f6"
688
- },
689
- newChatButtonPressed: {
690
- opacity: 0.6
691
- },
692
391
  emptyCenterTitleWrap: {
693
392
  flex: 1,
694
393
  alignItems: "center",
@@ -729,7 +428,6 @@ const styles = StyleSheet.create({
729
428
  bottom: 0,
730
429
  alignItems: "center",
731
430
  justifyContent: "flex-end",
732
- // borderTopWidth: 1,
733
431
  shadowColor: "#0f172a",
734
432
  shadowOpacity: 0.08,
735
433
  shadowRadius: 8,
@@ -745,6 +443,17 @@ const styles = StyleSheet.create({
745
443
  paddingTop: 10,
746
444
  paddingBottom: 4
747
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
+ },
748
457
  emptyModePillRow: {
749
458
  flexDirection: "row",
750
459
  alignItems: "center",