Conversation
Greptile OverviewGreptile SummaryThis PR integrates BrowserOS API to enable conversation history sync and user authentication. The implementation adds magic link and Google OAuth login, bidirectional sync for conversations, LLM providers, and scheduled tasks. Key Changes:
Issues Found:
The architectural approach is sound - proper separation between local/remote storage, graceful degradation for offline users, and good error handling with Sentry. However, the sequential network operations will cause poor UX for users with many conversations, providers, or scheduled jobs. Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Extension
participant AuthClient
participant BrowserOSAPI
participant SessionStorage
participant LocalStorage
Note over User,LocalStorage: Authentication Flow
User->>Extension: Open login page
Extension->>AuthClient: signIn.magicLink(email)
AuthClient->>BrowserOSAPI: POST /auth/magic-link
BrowserOSAPI-->>User: Send magic link email
User->>BrowserOSAPI: Click magic link
BrowserOSAPI-->>AuthClient: Set session cookie
AuthClient->>SessionStorage: Save session info
Extension->>Extension: Navigate to /home
Note over User,LocalStorage: Conversation Sync Flow
User->>Extension: Send message
Extension->>Extension: Generate conversation
Extension->>SessionStorage: Check login status
alt User logged in
Extension->>BrowserOSAPI: POST /graphql (CreateConversation)
BrowserOSAPI-->>Extension: Conversation created
Extension->>BrowserOSAPI: POST /graphql (AppendMessage)
BrowserOSAPI-->>Extension: Message saved
else User not logged in
Extension->>LocalStorage: Save conversation locally
end
Note over User,LocalStorage: Initial Sync on Login
SessionStorage->>Extension: Watch session change
Extension->>LocalStorage: Read local conversations
Extension->>BrowserOSAPI: POST /graphql (GetProfileId)
BrowserOSAPI-->>Extension: Profile ID
loop For each conversation
Extension->>BrowserOSAPI: POST /graphql (ConversationExists)
BrowserOSAPI-->>Extension: Check result
alt Conversation exists
Extension->>BrowserOSAPI: POST /graphql (GetUploadedMessageCount)
BrowserOSAPI-->>Extension: Message count
else New conversation
Extension->>BrowserOSAPI: POST /graphql (CreateConversation)
end
Extension->>BrowserOSAPI: POST /graphql (BulkCreateMessages)
BrowserOSAPI-->>Extension: Messages uploaded
end
Extension->>LocalStorage: Remove uploaded conversations
Note over User,LocalStorage: LLM Providers & Schedules Sync
Extension->>LocalStorage: Watch providers/schedules
Extension->>BrowserOSAPI: POST /graphql (SyncProviders)
Extension->>BrowserOSAPI: POST /graphql (SyncSchedules)
BrowserOSAPI-->>Extension: Sync complete
Note over User,LocalStorage: History Retrieval
User->>Extension: Open chat history
Extension->>SessionStorage: Check login status
alt User logged in
Extension->>BrowserOSAPI: POST /graphql (GetConversations)
BrowserOSAPI-->>Extension: Remote conversations
Extension->>User: Display remote history
else User not logged in
Extension->>LocalStorage: Read conversations
Extension->>User: Display local history
end
|
| for (const provider of providers) { | ||
| if (provider.type === 'browseros') continue | ||
|
|
||
| try { | ||
| const remote = remoteProviders.get(provider.id) | ||
|
|
||
| if (remote) { | ||
| if (isEqual(toComparable(provider), omit(remote, ['rowId']))) continue | ||
|
|
||
| await execute(UpdateLlmProviderForUploadDocument, { | ||
| input: { | ||
| rowId: provider.id, | ||
| patch: { | ||
| type: provider.type, | ||
| name: provider.name, | ||
| baseUrl: provider.baseUrl ?? null, | ||
| modelId: provider.modelId, | ||
| supportsImages: provider.supportsImages, | ||
| contextWindow: provider.contextWindow, | ||
| temperature: provider.temperature, | ||
| resourceName: provider.resourceName ?? null, | ||
| region: provider.region ?? null, | ||
| updatedAt: new Date(provider.updatedAt).toISOString(), | ||
| }, | ||
| }, | ||
| }) | ||
| } else { | ||
| await execute(CreateLlmProviderForUploadDocument, { | ||
| input: { | ||
| llmProvider: { | ||
| rowId: provider.id, | ||
| profileId, | ||
| type: provider.type, | ||
| name: provider.name, | ||
| baseUrl: provider.baseUrl ?? null, | ||
| modelId: provider.modelId, | ||
| supportsImages: provider.supportsImages, | ||
| contextWindow: provider.contextWindow, | ||
| temperature: provider.temperature, | ||
| resourceName: provider.resourceName ?? null, | ||
| region: provider.region ?? null, | ||
| createdAt: new Date(provider.createdAt).toISOString(), | ||
| updatedAt: new Date(provider.updatedAt).toISOString(), | ||
| }, | ||
| }, | ||
| }) | ||
| } | ||
| } catch (error) { | ||
| sentry.captureException(error, { | ||
| extra: { | ||
| providerId: provider.id, | ||
| providerName: provider.name, | ||
| }, | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
sequential GraphQL mutations in loop - creates network waterfall
use Promise.allSettled() to execute all provider updates in parallel
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/agent/lib/llm-providers/uploadLlmProvidersToGraphql.ts
Line: 65:120
Comment:
sequential GraphQL mutations in loop - creates network waterfall
use `Promise.allSettled()` to execute all provider updates in parallel
How can I resolve this? If you propose a fix, please make it concise.
Code ReviewI found 3 issues that need attention: 1. Missing
|
Integrates browser os to API to sync conversation history