vibefast-cli 0.7.12 → 0.7.14

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 (97) hide show
  1. package/dist/commands/add.d.ts.map +1 -1
  2. package/dist/commands/add.js +28 -2
  3. package/dist/commands/add.js.map +1 -1
  4. package/dist/commands/init.d.ts.map +1 -1
  5. package/dist/commands/init.js +5 -3
  6. package/dist/commands/init.js.map +1 -1
  7. package/package.json +1 -1
  8. package/recipes/audio-recorder/recipe.json +1 -1
  9. package/recipes/audio-recorder@latest.zip +0 -0
  10. package/recipes/charts/apps/native/src/app/{charts → (root)/(protected)/charts}/index.tsx +0 -3
  11. package/recipes/charts/apps/native/src/features/charts/app/preview.tsx +0 -3
  12. package/recipes/charts/apps/native/src/features/charts/components/area-chart.tsx +0 -3
  13. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +0 -3
  14. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +0 -3
  15. package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +0 -3
  16. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +0 -3
  17. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +0 -3
  18. package/recipes/charts/apps/native/src/features/charts/components/index.ts +0 -3
  19. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +0 -3
  20. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +0 -3
  21. package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +0 -3
  22. package/recipes/charts/apps/native/src/features/charts/components/stacked-area-chart.tsx +0 -3
  23. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +0 -3
  24. package/recipes/charts/apps/native/src/features/charts/data/mock-data.ts +0 -3
  25. package/recipes/charts/apps/native/src/features/charts/types/index.ts +0 -3
  26. package/recipes/charts/recipe.json +1 -1
  27. package/recipes/charts@latest.zip +0 -0
  28. package/recipes/chatbot/apps/native/src/api-client/chatbot.ts +83 -0
  29. package/recipes/chatbot/apps/native/src/app/{chatbot → (root)/(protected)/chatbot}/index.tsx +0 -1
  30. package/recipes/chatbot/apps/native/src/features/chatbot/app/index.tsx +56 -60
  31. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +0 -1
  32. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-input-bar.tsx +0 -1
  33. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +0 -1
  34. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +3 -26
  35. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +0 -1
  36. package/recipes/chatbot/apps/native/src/features/chatbot/components/image-preview-list.tsx +0 -1
  37. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +0 -1
  38. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/index.ts +0 -1
  39. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +0 -1
  40. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-error-boundary.tsx +0 -1
  41. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-list.tsx +10 -14
  42. package/recipes/chatbot/apps/native/src/features/chatbot/components/model-selector.tsx +0 -1
  43. package/recipes/chatbot/apps/native/src/features/chatbot/components/report-content-modal.tsx +0 -1
  44. package/recipes/chatbot/apps/native/src/features/chatbot/components/suggested-messages.tsx +0 -1
  45. package/recipes/chatbot/apps/native/src/features/chatbot/constants/models.ts +0 -1
  46. package/recipes/chatbot/apps/native/src/features/chatbot/constants/report-reasons.ts +0 -1
  47. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +0 -1
  48. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-config.ts +0 -1
  49. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +0 -1
  50. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +0 -1
  51. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-conversation.ts +0 -1
  52. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-image-picker.ts +0 -1
  53. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +0 -1
  54. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +0 -1
  55. package/recipes/chatbot/apps/native/src/features/chatbot/models/index.ts +0 -1
  56. package/recipes/chatbot/apps/native/src/features/chatbot/models/models.ts +0 -1
  57. package/recipes/chatbot/apps/native/src/features/chatbot/models/providers.ts +0 -1
  58. package/recipes/chatbot/apps/native/src/features/chatbot/models/types.ts +0 -1
  59. package/recipes/chatbot/apps/native/src/features/chatbot/services/file-uploader.ts +0 -1
  60. package/recipes/chatbot/apps/native/src/features/chatbot/services/message-handler-service.ts +0 -1
  61. package/recipes/chatbot/apps/native/src/features/chatbot/types/index.ts +5 -3
  62. package/recipes/chatbot/apps/native/src/features/chatbot/utils/chat-telemetry.ts +0 -1
  63. package/recipes/chatbot/packages/backend/convex/agents.ts +3 -4
  64. package/recipes/chatbot/packages/backend/convex/chatbot/content.ts +35 -0
  65. package/recipes/chatbot/packages/backend/convex/chatbot/sessions.ts +52 -0
  66. package/recipes/chatbot/packages/backend/convex/chatbot/streaming.ts +422 -0
  67. package/recipes/chatbot/packages/backend/convex/chatbot/telemetry.ts +56 -0
  68. package/recipes/chatbot/packages/backend/convex/chatbot/tools.ts +128 -0
  69. package/recipes/chatbot/packages/backend/convex/chatbotAgent.ts +6 -651
  70. package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -714
  71. package/recipes/chatbot/packages/backend/convex/tools/knowledgeRetrieval.ts +12 -7
  72. package/recipes/chatbot/recipe.json +6 -1
  73. package/recipes/chatbot@latest.zip +0 -0
  74. package/recipes/image-generator/apps/native/src/api-client/image-generator.ts +34 -0
  75. package/recipes/image-generator/packages/backend/convex/{imageGeneratorFunctions.ts → imageGenerator.ts} +1 -1
  76. package/recipes/image-generator/recipe.json +5 -1
  77. package/recipes/image-generator@latest.zip +0 -0
  78. package/recipes/payments/apps/native/src/api-client/payments.ts +44 -0
  79. package/recipes/payments/packages/backend/convex/payments/index.ts +13 -0
  80. package/recipes/payments/packages/backend/convex/payments.ts +119 -0
  81. package/recipes/payments/recipe.json +15 -2
  82. package/recipes/payments@latest.zip +0 -0
  83. package/recipes/quiz/recipe.json +1 -1
  84. package/recipes/quiz@latest.zip +0 -0
  85. package/recipes/tracker-app/recipe.json +1 -1
  86. package/recipes/tracker-app@latest.zip +0 -0
  87. package/recipes/voice-bot/recipe.json +1 -1
  88. package/recipes/voice-bot@latest.zip +0 -0
  89. package/src/commands/add.ts +108 -70
  90. package/src/commands/init.ts +5 -3
  91. package/tmp-npm-cache/_update-notifier-last-checked +0 -0
  92. /package/recipes/audio-recorder/apps/native/src/app/{audio-recorder → (root)/(protected)/audio-recorder}/index.tsx +0 -0
  93. /package/recipes/image-generator/apps/native/src/app/{image-generator → (root)/(protected)/image-generator}/gallery.tsx +0 -0
  94. /package/recipes/image-generator/apps/native/src/app/{image-generator → (root)/(protected)/image-generator}/index.tsx +0 -0
  95. /package/recipes/quiz/apps/native/src/app/{quiz → (root)/(protected)/quiz}/index.tsx +0 -0
  96. /package/recipes/tracker-app/apps/native/src/app/{tracker-app → (root)/(protected)/tracker-app}/index.tsx +0 -0
  97. /package/recipes/voice-bot/apps/native/src/app/{voice-bot → (root)/(protected)/voice-bot}/index.tsx +0 -0
@@ -1,11 +1,10 @@
1
-
2
1
  import { useAuthToken } from '@convex-dev/auth/react';
3
2
  import { api } from '@vibefast/backend/_generated/api';
4
3
  import type { Id } from '@vibefast/backend/_generated/dataModel';
5
4
  import { useQuery } from 'convex/react';
6
5
  import { Stack } from 'expo-router';
7
6
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
8
- import { Keyboard, TouchableWithoutFeedback, View } from 'react-native';
7
+ import { Keyboard, View } from 'react-native';
9
8
  import Animated from 'react-native-reanimated';
10
9
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
11
10
 
@@ -236,68 +235,65 @@ export default function ChatConversationScreen() {
236
235
 
237
236
  return (
238
237
  <NetworkConnectivityWrapper>
239
- <TouchableWithoutFeedback
240
- onPress={Keyboard.dismiss}
241
- accessible={false}
242
- touchSoundDisabled
243
- >
244
- <View style={{ flex: 1 }}>
245
- <Stack.Screen
246
- options={{
247
- title: translate('chatbot.title'),
248
- headerRight: clearChatButton,
249
- }}
238
+ <View style={{ flex: 1 }}>
239
+ <Stack.Screen
240
+ options={{
241
+ title: translate('chatbot.title'),
242
+ headerRight: clearChatButton,
243
+ }}
244
+ />
245
+ <FocusAwareStatusBar />
246
+
247
+ <View
248
+ style={{ flex: 1, paddingTop: insets.top }}
249
+ onTouchStart={() => Keyboard.dismiss()}
250
+ >
251
+ <MessageList
252
+ messages={messagesWithUrls}
253
+ onReportMessage={handleReportMessage}
254
+ testID="chat-conversation-screen"
250
255
  />
251
- <FocusAwareStatusBar />
252
-
253
- <View style={{ flex: 1, paddingTop: insets.top + 12 }}>
254
- <MessageList
255
- messages={messagesWithUrls}
256
- onReportMessage={handleReportMessage}
257
- testID="chat-conversation-screen"
258
- />
259
- </View>
256
+ </View>
260
257
 
261
- {statusLabel ? (
262
- <View className="pb-6 pl-5 pr-4 pt-2">
263
- <View className="flex-row gap-3">
264
- <Spinner
265
- size="sm"
266
- variant="pulse"
267
- color={theme.colors.foreground}
268
- />
269
- <Text className="text-base font-medium text-neutral-400 dark:text-neutral-500">
270
- {statusLabel}
271
- </Text>
272
- </View>
258
+ {statusLabel ? (
259
+ <View className="pb-6 pl-5 pr-4 pt-2">
260
+ <View className="flex-row gap-3">
261
+ <Spinner
262
+ size="sm"
263
+ variant="pulse"
264
+ color={theme.colors.foreground}
265
+ />
266
+ <Text className="text-base font-medium text-neutral-400 dark:text-neutral-500">
267
+ {statusLabel}
268
+ </Text>
273
269
  </View>
274
- ) : null}
275
-
276
- <ChatInputBar
277
- input={input}
278
- onInputChange={handleTextInputChange}
279
- onSubmit={handleSubmitWithKeyboardReset}
280
- isLoading={conversationLoading || isChatLoading}
281
- showSuggestedMessages={messages.length === 0}
282
- selectedModel={selectedModel}
283
- onModelChange={handleModelChange}
284
- />
285
-
286
- {/* Animated spacer for keyboard */}
287
- <Animated.View
288
- pointerEvents="none"
289
- style={keyboardCoordinator.keyboardPadding}
270
+ </View>
271
+ ) : null}
272
+
273
+ <ChatInputBar
274
+ input={input}
275
+ onInputChange={handleTextInputChange}
276
+ onSubmit={handleSubmitWithKeyboardReset}
277
+ isLoading={conversationLoading || isChatLoading}
278
+ showSuggestedMessages={messages.length === 0}
279
+ selectedModel={selectedModel}
280
+ onModelChange={handleModelChange}
281
+ />
282
+
283
+ {/* Animated spacer for keyboard */}
284
+ <Animated.View
285
+ pointerEvents="none"
286
+ style={keyboardCoordinator.keyboardPadding}
287
+ />
288
+
289
+ {messageToReport && (
290
+ <ReportContentModal
291
+ message={messageToReport}
292
+ onSubmit={handleSubmitReport}
293
+ onCancel={handleCancelReport}
290
294
  />
291
-
292
- {messageToReport && (
293
- <ReportContentModal
294
- message={messageToReport}
295
- onSubmit={handleSubmitReport}
296
- onCancel={handleCancelReport}
297
- />
298
- )}
299
- </View>
300
- </TouchableWithoutFeedback>
295
+ )}
296
+ </View>
301
297
  </NetworkConnectivityWrapper>
302
298
  );
303
299
  }
@@ -1,4 +1,3 @@
1
-
2
1
  import type React from 'react';
3
2
  import { View } from 'react-native';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import { AntDesign, Feather } from '@expo/vector-icons';
3
2
  import type React from 'react';
4
3
  import { useCallback, useMemo, useRef, useState } from 'react';
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * ChatMarkdown component for rendering markdown content in chat messages.
4
3
  *
@@ -1,7 +1,5 @@
1
-
2
1
  import { Feather, Ionicons } from '@expo/vector-icons';
3
2
  import type { Id } from '@vibefast/backend/_generated/dataModel';
4
- import type { Message } from 'ai'; // Base Message type
5
3
  import * as Clipboard from 'expo-clipboard';
6
4
  import React from 'react';
7
5
  import { View } from 'react-native';
@@ -9,45 +7,24 @@ import { View } from 'react-native';
9
7
  import { Image, Pressable, Text } from '@/components/ui';
10
8
  import { useToast } from '@/components/ui/utils';
11
9
  import { ChatMarkdown } from '@/features/chatbot/components/chat-markdown';
10
+ import type { AppMessage } from '@/features/chatbot/types';
12
11
  import { translate } from '@/lib';
13
12
  import { useThemeConfig } from '@/lib/use-theme-config';
14
13
 
15
- // Local definition for MessageContentPart compatible with Vercel AI SDK structure
16
- // This should be consistent with how `useChat` hook and AI SDK handle content.
17
- export type LocalMessageContentPart =
18
- | { type: 'text'; text: string }
19
- | { type: 'image'; image: string | URL }; // Allow string for input from client, server can convert to URL
20
-
21
- type ConvexAttachment = {
22
- type: 'image';
23
- storageId: Id<'_storage'>;
24
- url?: string; // This is now pre-fetched from the parent component
25
- fileName?: string;
26
- mimeType?: string;
27
- };
28
-
29
- // The message prop for ChatMessageBubble
30
- export type AppMessage = Omit<Message, 'content'> & {
31
- content: string | LocalMessageContentPart[]; // Content matches AI SDK
32
- attachments?: ConvexAttachment[]; // Custom prop for Convex-stored attachments
33
- };
34
-
35
14
  type ChatMessageBubbleProps = {
36
15
  message: AppMessage;
37
- onReportMessage?: (message: AppMessage) => void; // AppMessage type for handler
16
+ onReportMessage?: (message: AppMessage) => void;
38
17
  };
39
18
 
40
19
  const ConvexImage: React.FC<{
41
20
  storageId: Id<'_storage'>;
42
21
  isUser: boolean;
43
22
  fileName?: string;
44
- preloadedUrl?: string | null; // Pre-fetched URL from parent
23
+ preloadedUrl?: string | null;
45
24
  }> = React.memo(({ storageId, isUser, fileName, preloadedUrl }) => {
46
- // Use pre-loaded URL if available, otherwise show loading
47
25
  const imageUrl = preloadedUrl;
48
26
  const theme = useThemeConfig();
49
27
 
50
- // Fixed aspect ratio container to prevent layout shift when image loads
51
28
  return (
52
29
  <View
53
30
  className="my-1 w-48 overflow-hidden rounded-lg"
@@ -1,4 +1,3 @@
1
-
2
1
  import React from 'react';
3
2
  import { View } from 'react-native';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import { Feather } from '@expo/vector-icons';
3
2
  import type React from 'react';
4
3
  import { ActivityIndicator, ScrollView, View } from 'react-native';
@@ -1,4 +1,3 @@
1
-
2
1
  import { Feather } from '@expo/vector-icons';
3
2
  import React, { useCallback, useState } from 'react';
4
3
  import {
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Markdown rendering components for chatbot messages.
4
3
  *
@@ -1,4 +1,3 @@
1
-
2
1
  import React from 'react';
3
2
  import { ScrollView, View, type ViewStyle } from 'react-native';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import React from 'react';
3
2
  import { View } from 'react-native';
4
3
 
@@ -1,23 +1,16 @@
1
-
2
1
  import type { FlashListRef } from '@shopify/flash-list';
3
2
  import { FlashList } from '@shopify/flash-list';
4
- import type { Message } from 'ai';
5
3
  import React, { useCallback, useEffect, useRef } from 'react';
6
4
  import { Keyboard, View } from 'react-native';
7
5
 
8
- import { Text } from '@/components/ui';
9
- import type { AppMessage } from '@/features/chatbot/components/chat-message-bubble';
10
6
  import { ChatMessageBubble } from '@/features/chatbot/components/chat-message-bubble';
11
7
  import { MessageErrorBoundary } from '@/features/chatbot/components/message-error-boundary';
12
8
  import { useSmartScrollManager } from '@/features/chatbot/hooks/use-smart-scroll-manager';
13
- import { translate } from '@/lib';
9
+ import type { AppMessage } from '@/features/chatbot/types';
14
10
 
15
11
  type MessageListProps = {
16
- /** Array of messages to display */
17
- messages: AppMessage[]; // Use AppMessage
18
- /** Handler for reporting a message */
19
- onReportMessage?: (message: Message) => void; // Base Message type for handler is fine
20
- /** Test ID for E2E testing */
12
+ messages: AppMessage[];
13
+ onReportMessage?: (message: AppMessage) => void;
21
14
  testID?: string;
22
15
  };
23
16
 
@@ -140,10 +133,13 @@ export const MessageList: React.FC<MessageListProps> = ({
140
133
  return (
141
134
  <View className="flex-1 px-4" testID={testID}>
142
135
  {messages.length === 0 ? (
143
- <View className="flex-1 items-center justify-center px-6">
144
- <Text className="text-center text-base text-muted-foreground">
136
+ <View
137
+ className="flex-1 items-center justify-center px-6"
138
+ onTouchStart={handleTouchStart}
139
+ >
140
+ {/* <Text className="text-center text-base text-muted-foreground">
145
141
  {translate('chatbot.start_conversation')}
146
- </Text>
142
+ </Text> */}
147
143
  </View>
148
144
  ) : (
149
145
  <FlashList<AppMessage>
@@ -163,7 +159,7 @@ export const MessageList: React.FC<MessageListProps> = ({
163
159
  scrollEventThrottle={16}
164
160
  keyboardShouldPersistTaps="handled"
165
161
  keyboardDismissMode="on-drag"
166
- contentContainerStyle={{ paddingVertical: 16, paddingBottom: 8 }}
162
+ contentContainerStyle={{ paddingTop: 50, paddingBottom: 8 }}
167
163
  accessibilityLabel="Chat messages"
168
164
  accessibilityRole="list"
169
165
  testID="messages-flashlist"
@@ -1,4 +1,3 @@
1
-
2
1
  import { Feather } from '@expo/vector-icons';
3
2
  import type React from 'react';
4
3
  import { Alert, ScrollView, View } from 'react-native';
@@ -1,4 +1,3 @@
1
-
2
1
  import React, { useState } from 'react';
3
2
  import { View } from 'react-native';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import type React from 'react';
3
2
  import { useCallback } from 'react';
4
3
  import { ScrollView, View } from 'react-native';
@@ -1,4 +1,3 @@
1
-
2
1
  // DEPRECATED: This file has been moved to src/features/chatbot/models/
3
2
  // Please import from '@/features/chatbot/models' instead
4
3
  // This file is kept for backward compatibility
@@ -1,4 +1,3 @@
1
-
2
1
  export const REPORT_REASONS = [
3
2
  { label: 'Inaccurate Information', value: 'inaccurate' },
4
3
  { label: 'Offensive Content', value: 'offensive' },
@@ -1,4 +1,3 @@
1
-
2
1
  import type { Id } from '@vibefast/backend/_generated/dataModel';
3
2
  import { useCallback, useEffect, useRef } from 'react';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import type { Id } from '@vibefast/backend/_generated/dataModel';
3
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import type { Id } from '@vibefast/backend/_generated/dataModel';
3
2
  import React, { useCallback, useMemo, useState } from 'react';
4
3
  import { Alert, Keyboard } from 'react-native';
@@ -1,4 +1,3 @@
1
-
2
1
  import { useCallback, useEffect, useState } from 'react';
3
2
 
4
3
  import { defaultCacheService } from '@/core/cache';
@@ -1,4 +1,3 @@
1
-
2
1
  import type { Id } from '@vibefast/backend/_generated/dataModel';
3
2
  import { useEffect, useMemo, useState } from 'react';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import * as ImagePicker from 'expo-image-picker';
3
2
  import { useCallback } from 'react';
4
3
  import { Alert } from 'react-native';
@@ -1,4 +1,3 @@
1
-
2
1
  import { useCallback, useEffect, useRef } from 'react';
3
2
  import { Keyboard } from 'react-native';
4
3
  import {
@@ -1,4 +1,3 @@
1
-
2
1
  import type { FlashListRef } from '@shopify/flash-list';
3
2
  import { useCallback, useEffect, useMemo, useRef } from 'react';
4
3
  import type { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
@@ -1,4 +1,3 @@
1
-
2
1
  // Import directly to avoid circular dependencies
3
2
  import { DEFAULT_MODELS, MODELS } from './models';
4
3
  import type { ModelConfig, ModelId, Provider } from './types';
@@ -1,4 +1,3 @@
1
-
2
1
  import type { ModelConfig, Provider } from './types';
3
2
 
4
3
  export const MODELS: ModelConfig[] = [
@@ -1,4 +1,3 @@
1
-
2
1
  import type React from 'react';
3
2
 
4
3
  import { ClaudeIcon } from '@/components/ui/icons/claude';
@@ -1,4 +1,3 @@
1
-
2
1
  export type Provider = 'claude' | 'openai' | 'gemini';
3
2
 
4
3
  export type ModelCategory = 'free' | 'premium' | 'specialized';
@@ -1,4 +1,3 @@
1
-
2
1
  import { manipulateAsync, SaveFormat } from 'expo-image-manipulator';
3
2
  import { Image } from 'react-native';
4
3
 
@@ -1,4 +1,3 @@
1
-
2
1
  import type { Id } from '@vibefast/backend/_generated/dataModel';
3
2
  import { Alert } from 'react-native';
4
3
 
@@ -1,6 +1,4 @@
1
-
2
1
  import type { Id } from '@vibefast/backend/_generated/dataModel';
3
- import type { Message } from 'ai';
4
2
 
5
3
  export type LocalMessageContentPart =
6
4
  | { type: 'text'; text: string }
@@ -43,8 +41,12 @@ export type AgentStatus =
43
41
  startedAt: number;
44
42
  };
45
43
 
46
- export type AppMessage = Omit<Message, 'content'> & {
44
+ export type AppMessage = {
45
+ id: string;
46
+ role: 'user' | 'assistant' | 'data';
47
47
  content: string | LocalMessageContentPart[];
48
+ createdAt?: Date;
49
+ parts?: unknown; // Optional hook into AI SDK shapes when present
48
50
  attachments?: ConvexMessageAttachment[];
49
51
  toolCalls?: ToolCallRecord[];
50
52
  metadata?: MessageMetadata;
@@ -1,4 +1,3 @@
1
-
2
1
  import type { TelemetryMode } from '@/core/config';
3
2
  import { getChatTelemetryMode } from '@/core/config/telemetry';
4
3
 
@@ -1,6 +1,5 @@
1
1
  import { createGoogleGenerativeAI } from '@ai-sdk/google';
2
2
  import { openai } from '@ai-sdk/openai';
3
- import type { LanguageModelV1 } from '@ai-sdk/provider';
4
3
  import { Agent } from '@convex-dev/agent';
5
4
 
6
5
  import { components } from './_generated/api';
@@ -15,14 +14,14 @@ const google = createGoogleGenerativeAI();
15
14
  type ModelProvider = 'openai' | 'google';
16
15
 
17
16
  type ModelResolver = () => {
18
- model: LanguageModelV1;
17
+ model: any;
19
18
  provider: ModelProvider;
20
19
  modelId: string;
21
20
  };
22
21
 
23
22
  const PROVIDER_CHAT_FACTORIES: Record<
24
23
  ModelProvider,
25
- (modelId: string) => LanguageModelV1
24
+ (modelId: string) => unknown
26
25
  > = {
27
26
  openai: (modelId) => openai.chat(modelId),
28
27
  google: (modelId) => google.chat(modelId),
@@ -86,7 +85,7 @@ export function resolveChatModel(preferredModel?: string) {
86
85
 
87
86
  export const agent: Agent = new Agent(components.agent, {
88
87
  name: 'VibeFast Assistant',
89
- chat: MODEL_RESOLVERS[DEFAULT_MODEL]().model,
88
+ languageModel: MODEL_RESOLVERS[DEFAULT_MODEL]().model as any,
90
89
  instructions: `
91
90
  You are VibeFast, a proactive mobile AI assistant. Produce concise, friendly responses with clear structure.
92
91
 
@@ -0,0 +1,35 @@
1
+ import type { FilePart, ImagePart, TextPart } from 'ai';
2
+
3
+ import type { Doc } from '../_generated/dataModel';
4
+ import type { MutationCtx } from '../_generated/server';
5
+
6
+ export async function buildUserContent(
7
+ ctx: Pick<MutationCtx, 'storage'>,
8
+ message: Doc<'messages'>,
9
+ ): Promise<string | (TextPart | ImagePart | FilePart)[]> {
10
+ const attachments = message.attachments ?? [];
11
+ if (attachments.length === 0) {
12
+ return message.text ?? '';
13
+ }
14
+
15
+ const parts: (TextPart | ImagePart)[] = [];
16
+ if (message.text) {
17
+ parts.push({ type: 'text', text: message.text });
18
+ }
19
+
20
+ for (const attachment of attachments) {
21
+ try {
22
+ const url = await ctx.storage.getUrl(attachment.storageId);
23
+ if (url) {
24
+ parts.push({ type: 'image', image: new URL(url) });
25
+ }
26
+ } catch (error) {
27
+ console.error('[chatbotAgent] Failed to resolve attachment URL', {
28
+ storageId: attachment.storageId,
29
+ error,
30
+ });
31
+ }
32
+ }
33
+
34
+ return parts.length > 0 ? parts : (message.text ?? '');
35
+ }
@@ -0,0 +1,52 @@
1
+ import type { MutationCtx, QueryCtx } from '../_generated/server';
2
+ import type { Doc, Id } from '../_generated/dataModel';
3
+ import { agent, DEFAULT_MODEL } from '../agents';
4
+
5
+ type AgentSessionDoc = Doc<'agentSessions'>;
6
+
7
+ export async function getSessionForConversation(
8
+ ctx: Pick<MutationCtx, 'db'> | Pick<QueryCtx, 'db'>,
9
+ conversationId: Id<'conversations'>,
10
+ ) {
11
+ return await ctx.db
12
+ .query('agentSessions')
13
+ .withIndex('by_conversationId', (q) =>
14
+ q.eq('conversationId', conversationId),
15
+ )
16
+ .first();
17
+ }
18
+
19
+ export async function ensureAgentSession(
20
+ ctx: MutationCtx,
21
+ conversationId: Id<'conversations'>,
22
+ userId: Id<'users'>,
23
+ preferredModel?: string,
24
+ ): Promise<{ session: AgentSessionDoc; wasCreated: boolean }> {
25
+ const existing = await getSessionForConversation(ctx, conversationId);
26
+ if (existing) {
27
+ return { session: existing, wasCreated: false };
28
+ }
29
+
30
+ const { threadId } = await agent.createThread(ctx, {
31
+ userId,
32
+ });
33
+
34
+ const sessionId = await ctx.db.insert('agentSessions', {
35
+ conversationId,
36
+ userId,
37
+ agentThreadId: threadId,
38
+ activeStreamId: undefined,
39
+ lastUserMessageId: undefined,
40
+ lastAssistantMessageId: undefined,
41
+ preferredModel: preferredModel ?? DEFAULT_MODEL,
42
+ updatedAt: Date.now(),
43
+ lastErrorMessage: undefined,
44
+ lastErrorAt: undefined,
45
+ });
46
+
47
+ const session = await ctx.db.get(sessionId);
48
+ if (!session) {
49
+ throw new Error('Failed to create agent session');
50
+ }
51
+ return { session, wasCreated: true };
52
+ }