Files
BrowserOS/apps/agent/lib/conversations/uploadConversationsToGraphql.ts
Dani Akash 8639f2b20a feat: browseros API (#284)
* feat: created auth client

* feat: created login page for testing auth

* feat: setup logout page

* feat: setup graphql codegen

* feat: setup graphql + react query utils

* feat: setup queryprovider with localforage

* feat: created auth provider

* feat: update claude.md

* feat: documents for bulk conversation upload

* chore: install missing package

* fix: setup codegen to scan for .ts files

* chore: setup check conversation query

* feat: upload conversation by profileId

* chore: upload messages in batches

* feat: account for edge cases in conversation upload

* feat: delete uploaded conversations from localstorage

* feat: load conversation history from api

* feat: implement delete conversation using graphql

* feat: delete confirmation for conversation history

* fix: issue with clearing conversations after upload

* feat: implement pagination for graphql chat history

* chore: update CLAUDE.md

* chore: update claude.md

* feat: save conversations to server

* fix: handle streaming check on remote conversation save

* feat: restore conversation from graphql

* fix: timestamp issue on the chat history page

* feat: sync llm providers from background script

* feat: update llm providers on change via background script

* chore: added a try catch block

* feat: display incomplete providers in separate UI

* feat: delete provider on server when initiated by user

* feat: setup scheduled tasks storage to sync to graphql

* feat: auto run sync in background script

* fix: sync all keys of scheduled tasks based on updatedAt timestamp

* feat: added login dropdown on the sidebar

* feat: simplify sidenav header

* feat: update header design after login

* feat: setup profile page

* feat: added back button to profile page

* fix: scrollbar flash in profile page

* feat: finish login handshake

* feat: clear storage on logout

* fix: logout page style

* feat: added tooltip to encourage user to sign in

* feat: added back button to login page

* fix: upload logic for profile picture

* feat: account for profile name in sidebar branding

* chore: set file upload url from backend request

* chore: remove default placeholder from profile component

* chore: sync with main

* Revert "chore: sync with main"

This reverts commit 77e06b894ce30235d1bfa31c8e2699b34df423a5.

* Reapply "chore: sync with main"

This reverts commit dd921d97cc9794d1872e13689c881f68e4dfee47.

* chore: updated lock file

* fix: run codegen before build:ext

* fix: run codegen before build:gent

* fix: remove hardcoded localhost header in magic link

---------

Co-authored-by: Nikhil Sonti <nikhilsv92@gmail.com>
2026-01-30 23:33:57 +05:30

95 lines
2.9 KiB
TypeScript

import { execute } from '@/lib/graphql/execute'
import { sessionStorage } from '../auth/sessionStorage'
import { sentry } from '../sentry/sentry'
import { type Conversation, conversationStorage } from './conversationStorage'
import {
BulkCreateConversationMessagesDocument,
ConversationExistsDocument,
CreateConversationForUploadDocument,
GetProfileIdByUserIdDocument,
GetUploadedMessageCountDocument,
} from './graphql/uploadConversationDocument'
export async function uploadConversationsToGraphql(
conversations: Conversation[],
) {
if (conversations.length === 0) return
const sessionInfo = await sessionStorage.getValue()
const userId = sessionInfo?.user?.id
if (!userId) return
const profileResult = await execute(GetProfileIdByUserIdDocument, { userId })
const profileId = profileResult.profileByUserId?.rowId
if (!profileId) return
const uploadedIds: string[] = []
for (const conversation of conversations) {
try {
const existsResult = await execute(ConversationExistsDocument, {
pConversationId: conversation.id,
})
let uploadedCount = 0
if (existsResult.conversationExists) {
const countResult = await execute(GetUploadedMessageCountDocument, {
conversationId: conversation.id,
})
uploadedCount = countResult.conversationMessages?.totalCount ?? 0
if (uploadedCount >= conversation.messages.length) {
uploadedIds.push(conversation.id)
continue
}
} else {
await execute(CreateConversationForUploadDocument, {
input: {
conversation: {
rowId: conversation.id,
profileId,
lastMessagedAt: new Date(
conversation.lastMessagedAt,
).toISOString(),
createdAt: new Date(conversation.lastMessagedAt).toISOString(),
},
},
})
}
const remainingMessages = conversation.messages.slice(uploadedCount)
if (remainingMessages.length > 0) {
const BATCH_SIZE = 50
for (let i = 0; i < remainingMessages.length; i += BATCH_SIZE) {
const batch = remainingMessages.slice(i, i + BATCH_SIZE)
await execute(BulkCreateConversationMessagesDocument, {
input: {
pConversationId: conversation.id,
pMessages: batch.map((msg, batchIndex) => ({
orderIndex: uploadedCount + i + batchIndex,
message: msg,
})),
},
})
}
}
uploadedIds.push(conversation.id)
} catch (error) {
sentry.captureException(error, {
extra: {
conversationId: conversation.id,
messageCount: conversation.messages.length,
},
})
}
}
if (uploadedIds.length > 0) {
const remaining = conversations.filter((c) => !uploadedIds.includes(c.id))
conversationStorage.setValue(remaining)
}
}