fix(app): keep submitted prompts in place

Live canonical user rows consumed the oldest optimistic prompt even when a client message ID identified a later submission. Match identified rows exactly while retaining FIFO reconciliation for legacy rows.
This commit is contained in:
Mohamed Boudra
2026-07-21 19:31:40 +02:00
parent 5c93ac4aa5
commit c049e86fee
2 changed files with 50 additions and 1 deletions

View File

@@ -1457,6 +1457,52 @@ describe("turn lifecycle events", () => {
);
});
it("does not shift later prompts when an earlier optimistic prompt has no canonical echo", () => {
const staleTimestamp = new Date("2025-01-01T15:04:00Z");
const submittedTimestamp = new Date("2025-01-01T15:04:01Z");
const stalePrompt: StreamItem = {
kind: "user_message",
id: "msg_stale",
text: "first prompt without an echo",
timestamp: staleTimestamp,
optimistic: true,
};
const submittedPrompt: StreamItem = {
kind: "user_message",
id: "msg_submitted",
text: "later submitted prompt",
timestamp: submittedTimestamp,
optimistic: true,
};
const state = reduceStreamUpdate(
[stalePrompt, submittedPrompt],
{
type: "timeline",
provider: "codex",
item: {
type: "user_message",
text: "canonical rendered prompt",
messageId: "provider-owned-submitted",
clientMessageId: submittedPrompt.id,
},
},
new Date("2025-01-01T15:04:02Z"),
{ source: "live" },
);
assert.deepStrictEqual(state, [
stalePrompt,
{
kind: "user_message",
id: "provider-owned-submitted",
clientMessageId: submittedPrompt.id,
text: submittedPrompt.text,
timestamp: submittedPrompt.timestamp,
},
]);
});
it("appends a live server user message when no optimistic user message is pending", () => {
const state = reduceStreamUpdate(
[],

View File

@@ -365,7 +365,10 @@ function appendUserMessage(
const chunkSeed = chunk.trim() || chunk;
const entryId = messageId ?? createUniqueTimelineId(state, "user", chunkSeed, timestamp);
const optimisticIndex = state.findIndex(
(entry) => entry.kind === "user_message" && entry.optimistic,
(entry) =>
entry.kind === "user_message" &&
entry.optimistic &&
(clientMessageId === undefined || entry.id === clientMessageId),
);
const optimistic = optimisticIndex >= 0 ? (state[optimisticIndex] as UserMessageItem) : null;