Files
stealth-ai-relay/frontend/src/lib/convex/schema.ts
2026-01-25 16:44:59 +01:00

127 lines
3.6 KiB
TypeScript

import { defineSchema, defineTable } from 'convex/server';
import { v } from 'convex/values';
export default defineSchema({
users: defineTable({
telegramId: v.int64(),
telegramChatId: v.optional(v.int64()),
geminiApiKey: v.optional(v.string()),
systemPrompt: v.optional(v.string()),
followUpPrompt: v.optional(v.string()),
model: v.string(),
followUpModel: v.optional(v.string()),
activeChatId: v.optional(v.id('chats')),
ragCollectionMode: v.optional(
v.object({
ragDatabaseId: v.id('ragDatabases'),
activeSince: v.number()
})
)
}).index('by_telegram_id', ['telegramId']),
chats: defineTable({
userId: v.id('users'),
mnemonic: v.string(),
createdAt: v.number()
}).index('by_mnemonic', ['mnemonic']),
messages: defineTable({
chatId: v.id('chats'),
role: v.union(v.literal('user'), v.literal('assistant')),
content: v.string(),
imageBase64: v.optional(v.string()),
imageMediaType: v.optional(v.string()),
imageStorageId: v.optional(v.id('_storage')),
imagesBase64: v.optional(v.array(v.string())),
imagesMediaTypes: v.optional(v.array(v.string())),
followUpOptions: v.optional(v.array(v.string())),
source: v.union(v.literal('telegram'), v.literal('web')),
createdAt: v.number(),
isStreaming: v.optional(v.boolean())
})
.index('by_chat_id', ['chatId'])
.index('by_chat_id_and_created_at', ['chatId', 'createdAt']),
pendingGenerations: defineTable({
userId: v.id('users'),
chatId: v.id('chats'),
userMessage: v.string(),
imagesBase64: v.optional(v.array(v.string())),
imagesMediaTypes: v.optional(v.array(v.string())),
createdAt: v.number()
}),
pendingGenerationImages: defineTable({
pendingGenerationId: v.id('pendingGenerations'),
base64: v.string(),
mediaType: v.string(),
order: v.number()
}).index('by_pending_generation_id', ['pendingGenerationId']),
messageImages: defineTable({
messageId: v.id('messages'),
base64: v.string(),
mediaType: v.string(),
order: v.number()
}).index('by_message_id', ['messageId']),
devicePairings: defineTable({
chatId: v.id('chats'),
deviceId: v.string(),
hasCamera: v.boolean(),
pairedWithDeviceId: v.optional(v.string()),
lastSeen: v.number()
}).index('by_chat_id', ['chatId']),
pairingRequests: defineTable({
chatId: v.id('chats'),
fromDeviceId: v.string(),
status: v.union(v.literal('pending'), v.literal('accepted'), v.literal('rejected')),
createdAt: v.number()
}).index('by_chat_id', ['chatId']),
photoRequests: defineTable({
chatId: v.id('chats'),
requesterId: v.string(),
captureDeviceId: v.optional(v.string()),
status: v.union(
v.literal('pending'),
v.literal('countdown'),
v.literal('capture_now'),
v.literal('captured'),
v.literal('accepted'),
v.literal('rejected')
),
photoBase64: v.optional(v.string()),
photoMediaType: v.optional(v.string()),
thumbnailBase64: v.optional(v.string()),
createdAt: v.number()
}).index('by_chat_id', ['chatId']),
photoDrafts: defineTable({
chatId: v.id('chats'),
deviceId: v.string(),
base64: v.string(),
mediaType: v.string(),
createdAt: v.number()
}).index('by_chat_id_and_device_id', ['chatId', 'deviceId']),
ragDatabases: defineTable({
userId: v.id('users'),
name: v.string(),
createdAt: v.number()
})
.index('by_user_id', ['userId'])
.index('by_user_id_and_name', ['userId', 'name']),
ragConnections: defineTable({
userId: v.id('users'),
ragDatabaseId: v.id('ragDatabases'),
isGlobal: v.boolean(),
createdAt: v.number()
})
.index('by_user_id', ['userId'])
.index('by_user_id_and_rag_database_id', ['userId', 'ragDatabaseId'])
.index('by_rag_database_id', ['ragDatabaseId'])
});