Repository navigation
fix(mothership): close the remaining ways a chat send is lost, resent hot, or polled after unmount #8695
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
fix(mothership): close the remaining ways a chat send is lost, resent hot, or polled after unmount #8695
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
dbd1a64
fix(mothership): close the remaining ways a chat send is lost, resent…
waleedlatif1 b81fde7
fix(mothership): keep deleted chats empty across tabs and back off bu…
waleedlatif1 c704a62
fix(mothership): lift a chat's delete only when a later server read r…
waleedlatif1 ee245eb
fix(mothership): apply the restore check to every server read of a chat
waleedlatif1 aae0be6
test(mothership): use the central request mock in the restore read test
waleedlatif1 4f60309
fix(mothership): lift only the chat delete a read or restore saw
waleedlatif1 cf6651d
fix(mothership): keep a send refused as busy after the user switched …
waleedlatif1 cec0ebb
fix(mothership): check a deduplicated send's stream before adopting i…
waleedlatif1 be44382
fix(mothership): retry a deduplicated send whose stream lookup failed
waleedlatif1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
723 changes: 723 additions & 0 deletions
723
apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.dom.test.tsx
Large diffs are not rendered by default.
Oops, something went wrong.
187 changes: 147 additions & 40 deletions
187
apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
Large diffs are not rendered by default.
Oops, something went wrong.
119 changes: 119 additions & 0 deletions
119
apps/sim/hooks/queries/mothership-chat-history-restore.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| import { | ||
| apiClientRequestMock, | ||
| apiClientRequestMockFns, | ||
| } from '@sim/testing/mocks/api-client-request.mock' | ||
| import { reactQueryMock } from '@sim/testing/mocks/react-query.mock' | ||
| import { beforeEach, describe, expect, it, vi } from 'vitest' | ||
|
|
||
| vi.mock('@/lib/api/client/request', () => apiClientRequestMock) | ||
| vi.mock('@tanstack/react-query', () => reactQueryMock) | ||
|
|
||
| import { | ||
| fetchMothershipChatHistory, | ||
| type MothershipChatHistory, | ||
| useRestoreMothershipChat, | ||
| } from '@/hooks/queries/mothership-chats' | ||
| import { useMothershipQueueStore } from '@/stores/mothership-queue/store' | ||
|
|
||
| const mockRequestJson = apiClientRequestMockFns.mockRequestJson | ||
|
|
||
| const history: MothershipChatHistory = { | ||
| id: 'chat-1', | ||
| mode: 'agent', | ||
| title: 'Restored', | ||
| messages: [], | ||
| activeStreamId: null, | ||
| resources: [], | ||
| } | ||
|
|
||
| /** Whether the queue store takes a send for the chat, i.e. whether its delete still holds. */ | ||
| function takesSends(chatId: string): boolean { | ||
| useMothershipQueueStore.getState().enqueue(chatId, { id: 'probe', content: 'probe' }) | ||
| return useMothershipQueueStore.getState().queues[chatId] !== undefined | ||
| } | ||
|
|
||
| /** A server answer the test releases when it chooses. */ | ||
| function deferredAnswer(value: unknown): () => void { | ||
| let answer!: () => void | ||
| mockRequestJson.mockReturnValue( | ||
| new Promise((resolve) => { | ||
| answer = () => resolve(value) | ||
| }) | ||
| ) | ||
| return answer | ||
| } | ||
|
|
||
| /** The options `useRestoreMothershipChat` hands to `useMutation` (the mock returns them). */ | ||
| interface RestoreMutation { | ||
| mutationFn: (chatId: string) => Promise<void> | ||
| onMutate?: (chatId: string) => { deleteSeen?: number } | ||
| onSuccess: (data: undefined, chatId: string, context?: { deleteSeen?: number }) => void | ||
| } | ||
|
|
||
| async function restore(chatId: string, whileInFlight: () => void = () => {}) { | ||
| const mutation = useRestoreMothershipChat() as unknown as RestoreMutation | ||
| const context = mutation.onMutate?.(chatId) | ||
| const answer = deferredAnswer({ success: true }) | ||
| const done = mutation.mutationFn(chatId) | ||
| whileInFlight() | ||
| answer() | ||
| await done | ||
| mutation.onSuccess(undefined, chatId, context) | ||
| } | ||
|
|
||
| describe('lifting a chat delete', () => { | ||
| beforeEach(() => { | ||
| useMothershipQueueStore.getState().reset() | ||
| mockRequestJson.mockReset() | ||
| }) | ||
|
|
||
| it('reopens a chat this tab saw deleted once the server returns it again', async () => { | ||
| useMothershipQueueStore.getState().clearChat(history.id) | ||
| mockRequestJson.mockResolvedValue({ chat: history }) | ||
|
|
||
| await fetchMothershipChatHistory(history.id) | ||
|
|
||
| expect(takesSends(history.id)).toBe(true) | ||
| }) | ||
|
|
||
| it('keeps the delete when the read returning the chat began before it', async () => { | ||
| const answer = deferredAnswer({ chat: history }) | ||
| const read = fetchMothershipChatHistory(history.id) | ||
| useMothershipQueueStore.getState().clearChat(history.id) | ||
| answer() | ||
| await read | ||
|
|
||
| expect(takesSends(history.id)).toBe(false) | ||
| }) | ||
|
|
||
| it('keeps a newer delete that lands while a read after an earlier one is in flight', async () => { | ||
| useMothershipQueueStore.getState().clearChat(history.id) | ||
| const answer = deferredAnswer({ chat: history }) | ||
| const read = fetchMothershipChatHistory(history.id) | ||
| useMothershipQueueStore.getState().reopenChat(history.id) | ||
| useMothershipQueueStore.getState().clearChat(history.id) | ||
| answer() | ||
| await read | ||
|
|
||
| expect(takesSends(history.id)).toBe(false) | ||
| }) | ||
|
|
||
| it('reopens a chat restored from Recently Deleted', async () => { | ||
| useMothershipQueueStore.getState().clearChat(history.id) | ||
|
|
||
| await restore(history.id) | ||
|
|
||
| expect(takesSends(history.id)).toBe(true) | ||
| }) | ||
|
|
||
| it('keeps a delete that lands while the restore is in flight', async () => { | ||
| useMothershipQueueStore.getState().clearChat(history.id) | ||
|
|
||
| await restore(history.id, () => { | ||
| useMothershipQueueStore.getState().reopenChat(history.id) | ||
| useMothershipQueueStore.getState().clearChat(history.id) | ||
| }) | ||
|
|
||
| expect(takesSends(history.id)).toBe(false) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.