Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion apps/sim/stores/mothership-queue/store.dom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('useMothershipQueueStore rehydration', () => {
expect(plain?.admissionUnknown).toBeUndefined()
})

it('moves the reused id a saved Stop handoff carried onto the entry', async () => {
it('moves the reused id a saved Stop handoff carried onto the entry, over its own', async () => {
const seed = { chatId: 'chat-A', supersededStreamId: 'previous-response', stopRequired: true }
sessionStorage.setItem(
'mothership-queue',
Expand All @@ -96,6 +96,12 @@ describe('useMothershipQueueStore rehydration', () => {
admissionUnknown: false,
queuedSendHandoff: { id: 'never-sent', ...seed, userMessageId: 'attempt-2' },
},
{
id: 'both',
content: 'c',
resumeUserMessageId: 'withdrawn-attempt',
queuedSendHandoff: { id: 'both', ...seed, userMessageId: 'send-now-attempt' },
},
],
},
},
Expand All @@ -120,6 +126,14 @@ describe('useMothershipQueueStore rehydration', () => {
admissionUnknown: false,
queuedSendHandoff: { id: 'never-sent', ...seed },
},
{
id: 'both',
content: 'c',
/** The id that build sent: the handoff's, ahead of the entry's. */
resumeUserMessageId: 'send-now-attempt',
admissionUnknown: true,
queuedSendHandoff: { id: 'both', ...seed },
},
])
})
})
5 changes: 3 additions & 2 deletions apps/sim/stores/mothership-queue/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,13 @@ function withCurrentWaitFields(value: unknown): unknown {
if (!record) return value
const { retryRequired, heldUntilOnline, sendRetries, notBefore, ...rest } = record
/* An entry saved when its Stop handoff carried the reused id: that id is the
entry's `resumeUserMessageId` now. */
entry's `resumeUserMessageId` now. It wins over the entry's own, as it did
when that build picked the id to send. */
const seed = toRecordOrNull(rest.queuedSendHandoff)
if (seed && typeof seed.userMessageId === 'string') {
const { userMessageId: seedRequestId, ...seedRest } = seed
rest.queuedSendHandoff = seedRest
if (rest.resumeUserMessageId === undefined) rest.resumeUserMessageId = seedRequestId
rest.resumeUserMessageId = seedRequestId
}
return {
...rest,
Expand Down
12 changes: 7 additions & 5 deletions apps/sim/stores/mothership-queue/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ export type QueuedMothershipMessage = QueuedMessage & {
*/
retry?: SendRetry
/**
* Message id of a prior attempt at this send that an unmount cleanup
* withdrew. Reused when the entry is dispatched so the server deduplicates
* against that attempt — it never sees the client's abort, so a request it
* had already accepted still opened the chat and billed the turn. Persisted,
* so a retry after a reload deduplicates too.
* Message id of an earlier attempt at this send, the one id it goes out
* under: a send an unmount cleanup withdrew, a Send-now restored from its
* stored Stop handoff, or a dispatch put back in the queue. Reused when the
* entry is dispatched so the server deduplicates against that attempt — it
* never sees the client's abort, so a request it had already accepted still
* opened the chat and billed the turn. Persisted, so a retry after a reload
* deduplicates too.
*/
resumeUserMessageId?: string
}
Expand Down
Loading