1import type { ThreadFeedEntry } from "../../lib/threadActivity";
2import type { QueuedThreadMessage } from "../../state/thread-outbox-model";
3
4export type PendingThreadFeedEntry = ThreadFeedEntry & {
5 readonly pendingMessage?: QueuedThreadMessage;
6 readonly acknowledged?: boolean;
7};
8
9/** Append the outbox after all presented activity, until the server echoes each message. */
10export function appendPendingThreadMessages(
11 presentedFeed: ReadonlyArray<ThreadFeedEntry>,
12 feed: ReadonlyArray<ThreadFeedEntry>,
13 queuedMessages: ReadonlyArray<QueuedThreadMessage>,
14): ReadonlyArray<PendingThreadFeedEntry> {
15 if (queuedMessages.length === 0) return presentedFeed;
16 const deliveredIds = new Set(
17 feed.flatMap((entry) => (entry.type === "message" ? [entry.message.id] : [])),
18 );
19 return [
20 ...presentedFeed,
21 ...queuedMessages
22 .filter((message) => !deliveredIds.has(message.messageId))
23 .map((pendingMessage): PendingThreadFeedEntry => ({
24 type: "message",
25 id: pendingMessage.messageId,
26 createdAt: pendingMessage.createdAt,
27 pendingMessage,
28 message: {
29 id: pendingMessage.messageId,
30 role: "user",
31 text: pendingMessage.text,
32 attachments: [],
33 context: pendingMessage.context,
34 createdAt: pendingMessage.createdAt,
35 updatedAt: pendingMessage.createdAt,
36 runId: null,
37 streaming: false,
38 visibility: "local",
39 sourceThreadId: pendingMessage.threadId,
40 },
41 })),
42 ];
43}