[eric] chat: keep the user message on remount for any live session, not just still-pending ones (ws echo clears pending instantly)

This commit is contained in:
eric
2026-06-01 12:44:55 -07:00
parent b30ccb061e
commit 2718bddaf7
+20 -14
View File
@@ -1227,27 +1227,33 @@ const agentsSlice = createSlice({
.addCase(fetchSession.fulfilled, (state, action) => {
const session = action.payload;
const existing = state.sessions[session.id];
// Preserve optimistic-pending messages the server snapshot doesn't carry
// yet. On remount mid-stream (leave the chat + come back) this fetch's
// snapshot predates the just-sent user turn, so a blind replace wiped the
// user's own message bubble while the assistant stream (separate slice)
// kept going. Carry forward any local pending message not already echoed
// in the snapshot; the WS echo / next fetch dedupes it by client_message_id.
// Preserve local messages the server snapshot doesn't carry yet. On
// remount mid-stream (leave the chat + come back) this fetch's snapshot
// predates the just-sent user turn, so a blind replace wiped the user's
// own bubble while the assistant stream (separate slice) kept going.
// The WS echo clears optimistic_status the instant it arrives, so the
// message is usually "confirmed but not yet server-persisted" rather than
// still 'pending' (that's why a pending-only filter missed it). Gate on
// the session being LIVE: on a running/streaming session, carry forward
// any local message the snapshot lacks; on a settled session the snapshot
// is authoritative (so a server-side delete isn't resurrected).
const incomingMsgs = session.messages ?? [];
const liveStatus = session.status === 'running' || session.status === 'waiting_approval';
const incomingClientIds = new Set(
incomingMsgs.map((m) => m.client_message_id).filter(Boolean),
);
const incomingIds = new Set(incomingMsgs.map((m) => m.id));
const survivingOptimistic = (existing?.messages ?? []).filter(
(m) =>
m.optimistic_status === 'pending' &&
!(m.client_message_id && incomingClientIds.has(m.client_message_id)) &&
!incomingIds.has(m.id),
);
const surviving = liveStatus
? (existing?.messages ?? []).filter(
(m) =>
!incomingIds.has(m.id) &&
!(m.client_message_id && incomingClientIds.has(m.client_message_id)),
)
: [];
state.sessions[session.id] = {
...session,
messages: survivingOptimistic.length
? [...incomingMsgs, ...survivingOptimistic]
messages: surviving.length
? [...incomingMsgs, ...surviving]
: incomingMsgs,
pending_approvals: session.pending_approvals ?? existing?.pending_approvals ?? [],
tool_group_meta: session.tool_group_meta ?? existing?.tool_group_meta ?? {},