fix: discard reverted optimistic messages after send
Removes reverted branch messages from the optimistic shadow after a successful send Prevents deleted messages from being merged back in on the next tail refresh Covers the cleanup behavior with an updated test
This commit is contained in:
@@ -626,7 +626,7 @@ describe("optimisticSend target directory", () => {
|
|||||||
expect(currentStore.getState().session_status["session-new"]).toBe(undefined)
|
expect(currentStore.getState().session_status["session-new"]).toBe(undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("commits the new branch locally when sending after a revert", async () => {
|
test("commits the new branch locally and discards its optimistic shadow when sending after a revert", async () => {
|
||||||
const retainedMessage = { id: "msg_1", role: "user", sessionID: "session-reverted" } as Message
|
const retainedMessage = { id: "msg_1", role: "user", sessionID: "session-reverted" } as Message
|
||||||
const revertedMessage = { id: "msg_2", role: "user", sessionID: "session-reverted" } as Message
|
const revertedMessage = { id: "msg_2", role: "user", sessionID: "session-reverted" } as Message
|
||||||
const targetStore = createStore({}, {
|
const targetStore = createStore({}, {
|
||||||
@@ -636,18 +636,21 @@ describe("optimisticSend target directory", () => {
|
|||||||
})
|
})
|
||||||
const childStores = createChildStores([["/target/project", targetStore]])
|
const childStores = createChildStores([["/target/project", targetStore]])
|
||||||
let optimisticMessage: Message | null = null
|
let optimisticMessage: Message | null = null
|
||||||
|
const optimisticShadow = new Set([revertedMessage.id])
|
||||||
|
|
||||||
const { optimisticSend, setActionRefs, setOptimisticRefs } = await import("./session-actions")
|
const { optimisticSend, setActionRefs, setOptimisticRefs } = await import("./session-actions")
|
||||||
setActionRefs(mockSdk as unknown as OpencodeClient, childStores, () => "/target/project")
|
setActionRefs(mockSdk as unknown as OpencodeClient, childStores, () => "/target/project")
|
||||||
setOptimisticRefs(
|
setOptimisticRefs(
|
||||||
(input) => {
|
(input) => {
|
||||||
optimisticMessage = input.message
|
optimisticMessage = input.message
|
||||||
|
optimisticShadow.add(input.message.id)
|
||||||
targetStore.setState((state) => ({
|
targetStore.setState((state) => ({
|
||||||
message: { ...state.message, [input.sessionID]: [...(state.message[input.sessionID] ?? []), input.message] },
|
message: { ...state.message, [input.sessionID]: [...(state.message[input.sessionID] ?? []), input.message] },
|
||||||
part: { ...state.part, [input.message.id]: input.parts },
|
part: { ...state.part, [input.message.id]: input.parts },
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
() => {},
|
() => {},
|
||||||
|
(input) => optimisticShadow.delete(input.messageID),
|
||||||
)
|
)
|
||||||
|
|
||||||
await optimisticSend({
|
await optimisticSend({
|
||||||
@@ -665,6 +668,8 @@ describe("optimisticSend target directory", () => {
|
|||||||
(optimisticMessage as unknown as Message).id,
|
(optimisticMessage as unknown as Message).id,
|
||||||
])
|
])
|
||||||
expect(targetStore.getState().part.msg_2).toBe(undefined)
|
expect(targetStore.getState().part.msg_2).toBe(undefined)
|
||||||
|
expect(optimisticShadow.has(revertedMessage.id)).toBe(false)
|
||||||
|
expect(optimisticShadow.has((optimisticMessage as unknown as Message).id)).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("restores the reverted branch when sending fails", async () => {
|
test("restores the reverted branch when sending fails", async () => {
|
||||||
|
|||||||
@@ -937,6 +937,17 @@ export async function optimisticSend(input: {
|
|||||||
const part = { ...stateBeforeSend.part }
|
const part = { ...stateBeforeSend.part }
|
||||||
for (const revertedMessage of revertedMessages) delete part[revertedMessage.id]
|
for (const revertedMessage of revertedMessages) delete part[revertedMessage.id]
|
||||||
store.setState({ session, message, part })
|
store.setState({ session, message, part })
|
||||||
|
|
||||||
|
// A server-backed user message can still remain in the loader's optimistic
|
||||||
|
// shadow until a page fetch confirms it. Forget the reverted branch there
|
||||||
|
// too, or the next tail refresh will merge those deleted messages back in.
|
||||||
|
for (const revertedMessage of revertedMessages) {
|
||||||
|
_optimisticConfirm?.({
|
||||||
|
sessionID: input.sessionId,
|
||||||
|
directory: targetDirectory,
|
||||||
|
messageID: revertedMessage.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageID = ascendingId("msg")
|
const messageID = ascendingId("msg")
|
||||||
|
|||||||
Reference in New Issue
Block a user