fix: persist provider on default conversation to prevent tab flickering#1320
fix: persist provider on default conversation to prevent tab flickering#1320arnestrickmann merged 2 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR fixes tab flickering caused by the default conversation's Key changes and findings:
Confidence Score: 3/5
Sequence DiagramsequenceDiagram
participant UI as ChatInterface (renderer)
participant IPC as dbIpc (main)
participant DB as DatabaseService (main)
Note over UI: task.id or task.agentId changes
UI->>UI: set cancelled=false
UI->>IPC: getConversations(task.id)
IPC->>DB: getConversations(task.id)
DB-->>UI: conversations[]
alt conversations exist
UI->>UI: setConversations / setActiveConversationId / setAgent
opt no active conversation found
UI->>IPC: setActiveConversation({ taskId, conversationId })
end
UI->>UI: if (!cancelled) setConversationsLoaded(true)
else no conversations (first load / legacy task)
UI->>UI: taskAgent = task.agentId || agent (stale!)
UI->>IPC: getOrCreateDefaultConversation({ taskId, provider: taskAgent })
IPC->>DB: getOrCreateDefaultConversation(taskId, provider)
alt existing row with null provider → backfill
DB->>DB: UPDATE conversations SET provider=? WHERE id=?
DB-->>UI: conversation (provider backfilled)
else existing row with provider
DB-->>UI: conversation (unchanged)
else no row → create
DB->>DB: saveConversation({ id, taskId, provider, isMain, isActive })
DB-->>UI: conversation (provider saved atomically)
end
UI->>UI: if (!cancelled) setConversations / setAgent / setConversationsLoaded
end
Note over UI: cleanup: cancelled=true on unmount/re-run
Last reviewed commit: 9b3764a |
| // This ensures existing tasks always have at least one conversation | ||
| // (preserves pre-multi-chat behavior) | ||
| const defaultConversation = await rpc.db.getOrCreateDefaultConversation(task.id); | ||
| const taskAgent = (task.agentId || agent) as string; |
There was a problem hiding this comment.
Stale agent still leaks via || agent fallback
The PR description states a goal of "replacing || agent fallbacks with ?? 'claude' to avoid leaking the current agent selection into unrelated conversation tabs", but this line still uses || agent as a fallback for tasks without task.agentId.
Because agent is intentionally excluded from the effect's dependency array (line 234: // agent is intentionally not included as a dependency), it captures the agent value from the previous task at effect-run time. For tasks created before agentId was introduced (i.e. task.agentId is null/undefined), this causes the old task's agent to be atomically saved as the provider for the new task's default conversation — exactly the stale-agent leak the PR aims to fix.
Using ?? 'claude' here is consistent with every other fallback changed in this PR and avoids persisting a potentially wrong provider to the database.
| const taskAgent = (task.agentId || agent) as string; | |
| const taskAgent = (task.agentId ?? 'claude') as string; |
| // Save the agent to the conversation | ||
| await rpc.db.saveConversation(conversationWithAgent); | ||
| setConversationsLoaded(true); | ||
| setAgent((defaultConversation.provider || taskAgent) as Agent); |
There was a problem hiding this comment.
Fallback contradicts "guaranteed provider" comment
The comment directly above (line 215) reads "Provider is guaranteed by getOrCreateDefaultConversation (saves atomically)", yet this line still falls back to taskAgent via ||. These two statements are in tension:
- If the guarantee holds (provider is always non-null when
taskAgentis truthy, which it always is here), the|| taskAgentbranch is dead code. - If the guarantee does not hold for some edge case, the comment is misleading.
Using ?? over || is also more precise: || would replace an empty string "" with taskAgent, while ?? only replaces null/undefined, which is consistent with the Conversation type's nullable provider field.
| setAgent((defaultConversation.provider || taskAgent) as Agent); | |
| setAgent((defaultConversation.provider ?? taskAgent) as Agent); |
# Conflicts: # src/renderer/components/ChatInterface.tsx # src/renderer/lib/taskCreationService.ts
Summary
Fixes a bug where conversation tabs would flicker or show incorrect agent names because the default conversation's
providerfield was not being saved atomically during creation.Changes
DatabaseService.getOrCreateDefaultConversation: Accept optionalproviderparameter and persist it when creating new conversations. Backfillsprovideron existing conversations that were saved asnull.dbIpc.ts: Update IPC signature to pass{ taskId, provider }object instead of baretaskId.ChatInterface.tsx:providerwhen callinggetOrCreateDefaultConversation, eliminating the separatesaveConversationround-trip|| agentfallbacks with?? 'claude'to avoid leaking the current agent selection into unrelated conversation tabstaskCreationService.ts: Passproviderwhen creating default conversation during task creation with issue contextTest plan