Skip to content

Fix AI chat infinite loading shimmer on empty workspace#17521

Merged
FelixMalfait merged 3 commits intomainfrom
fix/ai-chat-loading-shimmer-infinite-loop
Jan 28, 2026
Merged

Fix AI chat infinite loading shimmer on empty workspace#17521
FelixMalfait merged 3 commits intomainfrom
fix/ai-chat-loading-shimmer-infinite-loop

Conversation

@FelixMalfait
Copy link
Copy Markdown
Member

Summary

Fixes an issue where the AI chat would show loading shimmers indefinitely when opened on a workspace with no conversation history.

Root cause: The isLoading state in useAgentChat included !currentAIChatThread. On workspaces with no chat threads, currentAIChatThread remained null, causing isLoading to be permanently true.

Changes:

  • Remove !currentAIChatThread from isLoading calculation in useAgentChat - this state should only reflect streaming/file selection status
  • Auto-create a chat thread in useAgentChatData when the threads query returns empty, ensuring a valid thread exists for the useChat hook to initialize properly
  • Add primary font color to empty state title for better visibility

Test plan

  1. Create a new workspace or use a workspace with no AI chat history
  2. Open the AI chat
  3. Verify the empty state shows (not infinite loading shimmer)
  4. Send a message and verify it works correctly

Made with Cursor

When opening the AI chat on a workspace with no conversation history,
the loading shimmer would display indefinitely because:

1. `isLoading` in useAgentChat included `!currentAIChatThread`
2. With no threads, `currentAIChatThread` stayed null
3. This made `isLoading` permanently true

The fix:
- Remove `!currentAIChatThread` from `isLoading` calculation in useAgentChat
- Auto-create a chat thread in useAgentChatData when the threads query
  returns empty, ensuring a valid thread exists for the useChat hook
- Add primary font color to empty state title for better visibility

Co-authored-by: Cursor <cursoragent@cursor.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Jan 28, 2026

Greptile Overview

Greptile Summary

Fixed infinite loading shimmer in AI chat on empty workspaces by correcting the isLoading state logic and ensuring a thread exists before the chat UI initializes.

Key Changes:

  • Removed !currentAIChatThread from isLoading calculation in useAgentChat - this check caused permanent loading state when no thread existed
  • Added auto-creation of chat thread in useAgentChatData when threads query returns empty, ensuring the useChat hook always has a valid thread ID
  • Added primary font color to empty state title for improved visibility

How it works:
The fix separates concerns between two loading states: (1) useAgentChatData.isLoading handles data fetching (threads/messages), and (2) useAgentChat.isLoading handles streaming and file selection. When no threads exist, a new thread is auto-created in the onCompleted callback, setting currentAIChatThread before the messages query runs. This ensures useChat receives a valid thread ID and the empty state renders correctly instead of showing infinite shimmer.

Confidence Score: 4/5

  • This PR is safe to merge with low risk - the logic is sound and addresses the root cause correctly
  • Score reflects clean fix with proper separation of concerns. Minor concern about potential race condition in auto-creation logic if query fires multiple times before state updates, though Apollo Client's deduplication should handle this. Otherwise changes are minimal, focused, and don't introduce new complexity.
  • Pay attention to useAgentChatData.ts for potential race conditions with auto-creation

Important Files Changed

Filename Overview
packages/twenty-front/src/modules/ai/hooks/useAgentChat.ts Removed !currentAIChatThread from isLoading calculation and added thread check to handleSendMessage guard
packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts Auto-creates chat thread when threads query returns empty to ensure valid thread exists
packages/twenty-front/src/modules/ai/components/AIChatEmptyState.tsx Added primary color to title for better visibility

Sequence Diagram

sequenceDiagram
    participant User
    participant AIChatTab
    participant AgentChatProvider
    participant useAgentChatData
    participant useAgentChat
    participant GraphQL

    User->>AIChatTab: Opens AI chat
    AIChatTab->>AgentChatProvider: Render
    AgentChatProvider->>useAgentChatData: Initialize
    useAgentChatData->>GraphQL: useGetChatThreadsQuery()
    
    alt No existing threads (empty workspace)
        GraphQL-->>useAgentChatData: threads = []
        useAgentChatData->>GraphQL: createChatThread()
        GraphQL-->>useAgentChatData: newThread { id }
        useAgentChatData->>useAgentChatData: setCurrentAIChatThread(newThread.id)
    else Existing threads found
        GraphQL-->>useAgentChatData: threads = [thread1, ...]
        useAgentChatData->>useAgentChatData: setCurrentAIChatThread(threads[0].id)
    end
    
    useAgentChatData->>GraphQL: useGetChatMessagesQuery(threadId)
    GraphQL-->>useAgentChatData: messages = []
    useAgentChatData-->>AgentChatProvider: { uiMessages: [], isLoading: false }
    
    AgentChatProvider->>useAgentChat: Initialize with uiMessages
    Note over useAgentChat: isLoading = isStreaming || hasSelectedFiles<br/>(no longer checks !currentAIChatThread)
    useAgentChat-->>AgentChatProvider: { isLoading: false }
    
    AgentChatProvider-->>AIChatTab: { isLoading: false, messages: [] }
    AIChatTab->>AIChatTab: Render AIChatEmptyState
    AIChatTab-->>User: Shows empty state (not infinite shimmer)
Loading

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 28, 2026

🚀 Preview Environment Ready!

Your preview environment is available at: http://bore.pub:35968

This environment will automatically shut down when the PR is closed or after 5 hours.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 3 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts">

<violation number="1" location="packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts:65">
P2: Auto-creating the first thread doesn’t clear `agentChatUsageState`, so usage from a previous thread/workspace can persist in the UI. Consider resetting usage before creating the initial thread.</violation>

<violation number="2" location="packages/twenty-front/src/modules/ai/hooks/useAgentChatData.ts:65">
P2: Race condition: `createChatThread()` is called when threads are empty, but `currentAIChatThread` is set asynchronously in the mutation's `onCompleted`. If the component re-renders before the mutation completes, the query may fire again and call `createChatThread()` multiple times, creating duplicate threads. Consider using a ref to track whether thread creation is in progress to prevent duplicate calls.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

- Add isCreatingChatThreadState Recoil atom to track thread creation
- Use state to prevent duplicate createChatThread calls during race conditions
- Reset agentChatUsageState when creating initial thread (consistent with useCreateNewAIChatThread)
- Add onError handler to reset creation state on failure

Co-authored-by: Cursor <cursoragent@cursor.com>
@FelixMalfait FelixMalfait merged commit 81eaee8 into main Jan 28, 2026
90 of 92 checks passed
@FelixMalfait FelixMalfait deleted the fix/ai-chat-loading-shimmer-infinite-loop branch January 28, 2026 16:36
@twenty-eng-sync
Copy link
Copy Markdown

Hey @FelixMalfait! After you've done the QA of your Pull Request, you can mark it as done here. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant