Skip to content

Commit ed4ea7c

Browse files
committed
fix(chat): deliver an aborted chatless send to the live replacement surface
The settling remount's consumer checks handoff storage before the restore microtask re-persists it, so the stored handoff sat unread until a navigation. The replacement surface's send listener IS registered by restore time — deliver the message directly through the claimable send event, keeping the stored handoff as the no-surface fallback.
1 parent cd23af8 commit ed4ea7c

2 files changed

Lines changed: 39 additions & 7 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.mount-send.test.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,31 @@ describe('useChat mount-settling send recovery', () => {
143143
vi.clearAllMocks()
144144
})
145145

146+
it('delivers an aborted chatless send directly to a live replacement surface', async () => {
147+
const received: string[] = []
148+
const claim = (event: Event) => {
149+
received.push((event as CustomEvent<{ message: string }>).detail.message)
150+
event.preventDefault()
151+
}
152+
window.addEventListener('mothership-send-message', claim)
153+
154+
try {
155+
const { getResult, unmount } = renderUseChat()
156+
await act(async () => {
157+
void getResult().sendMessage('hello from the palette')
158+
})
159+
await waitFor(() => state.postCalls === 1)
160+
161+
unmount()
162+
await waitFor(() => received.length === 1)
163+
164+
expect(received).toEqual(['hello from the palette'])
165+
expect(window.localStorage.getItem('sim_mothership_handoff')).toBeNull()
166+
} finally {
167+
window.removeEventListener('mothership-send-message', claim)
168+
}
169+
})
170+
146171
it('re-persists an aborted chatless send as a handoff for the next mount', async () => {
147172
const { getResult, unmount } = renderUseChat()
148173

apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import {
9292
migrateDesktopChatScopes,
9393
PENDING_CHAT_KEY_PREFIX,
9494
} from '@/lib/desktop/chat-scope'
95+
import { sendMothershipMessage } from '@/lib/mothership/events'
9596
import { initTerminalTransport } from '@/lib/terminal/transport'
9697
import { getQueryClient } from '@/app/_shell/providers/get-query-client'
9798
import { useFilePreviewController } from '@/app/workspace/[workspaceId]/home/hooks/preview'
@@ -4518,13 +4519,19 @@ export function useChat(
45184519
dispatchChatKey.startsWith(PENDING_CHAT_KEY_PREFIX) &&
45194520
!msg.fileAttachments?.length
45204521
) {
4521-
MothershipHandoffStorage.store(
4522-
{
4523-
message: msg.content,
4524-
...(msg.contexts?.length ? { contexts: msg.contexts } : {}),
4525-
},
4526-
workspaceId
4527-
)
4522+
/* The settling remount has already run its mount effects by the time
4523+
this microtask executes, so the replacement surface's send listener
4524+
is live — deliver directly. The stored-handoff fallback covers a
4525+
real navigation away, where the next mount's consumer picks it up. */
4526+
if (!sendMothershipMessage(msg.content, msg.contexts)) {
4527+
MothershipHandoffStorage.store(
4528+
{
4529+
message: msg.content,
4530+
...(msg.contexts?.length ? { contexts: msg.contexts } : {}),
4531+
},
4532+
workspaceId
4533+
)
4534+
}
45284535
return
45294536
}
45304537
useMothershipQueueStore.getState().insertAt(dispatchChatKey, originalIndex, msg)

0 commit comments

Comments
 (0)