| 1 | import type { ThreadFeedEntry } from "../../lib/threadActivity"; |
| 2 | import type { QueuedThreadMessage } from "../../state/thread-outbox-model"; |
| 3 | |
| 4 | export 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. */ |
| 10 | export 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 | } |