diff --git a/packages/ui/src/stores/message-v2/bridge.ts b/packages/ui/src/stores/message-v2/bridge.ts index 6642f107..7b1b35be 100644 --- a/packages/ui/src/stores/message-v2/bridge.ts +++ b/packages/ui/src/stores/message-v2/bridge.ts @@ -5,7 +5,7 @@ import { getQuestionCallId, getQuestionMessageId } from "../../types/question" import type { Message, MessageInfo, ClientPart } from "../../types/message" import type { Session } from "../../types/session" import { messageStoreBus } from "./bus" -import type { MessageStatus, SessionRevertState } from "./types" +import type { MessageStatus, ReplaceMessageIdOptions, SessionRevertState } from "./types" interface SessionMetadata { id: string @@ -121,10 +121,10 @@ export function applyPartDeltaV2( }) } -export function replaceMessageIdV2(instanceId: string, oldId: string, newId: string): void { +export function replaceMessageIdV2(instanceId: string, oldId: string, newId: string, options?: Omit): void { if (!oldId || !newId || oldId === newId) return const store = messageStoreBus.getOrCreate(instanceId) - store.replaceMessageId({ oldId, newId }) + store.replaceMessageId({ oldId, newId, ...(options ?? {}) }) } function extractPermissionMessageId(permission: PermissionRequestLike): string | undefined { diff --git a/packages/ui/src/stores/message-v2/instance-store.ts b/packages/ui/src/stores/message-v2/instance-store.ts index bc2bb1f3..12f70bc3 100644 --- a/packages/ui/src/stores/message-v2/instance-store.ts +++ b/packages/ui/src/stores/message-v2/instance-store.ts @@ -586,10 +586,10 @@ export function createInstanceMessageStore(instanceId: string, hooks?: MessageSt bufferPendingPart({ messageId: input.messageId, part: input.part, receivedAt: Date.now() }) return } - + const partId = ensurePartId(input.messageId, input.part, message.partIds.length) const cloned = clonePart(input.part) - + setState( "messages", input.messageId, @@ -792,6 +792,8 @@ export function createInstanceMessageStore(instanceId: string, hooks?: MessageSt id: options.newId, isEphemeral: false, updatedAt: Date.now(), + partIds: options.clearParts ? [] : existing.partIds, + parts: options.clearParts ? {} : existing.parts, } setState("messages", options.newId, cloned) diff --git a/packages/ui/src/stores/message-v2/types.ts b/packages/ui/src/stores/message-v2/types.ts index 4d41cabc..986990a3 100644 --- a/packages/ui/src/stores/message-v2/types.ts +++ b/packages/ui/src/stores/message-v2/types.ts @@ -152,6 +152,7 @@ export interface PartUpdateInput { export interface ReplaceMessageIdOptions { oldId: string newId: string + clearParts?: boolean } export interface ScrollCacheKey { diff --git a/packages/ui/src/stores/session-actions.ts b/packages/ui/src/stores/session-actions.ts index f94f6ce7..8e193c6d 100644 --- a/packages/ui/src/stores/session-actions.ts +++ b/packages/ui/src/stores/session-actions.ts @@ -94,7 +94,7 @@ async function sendMessage( } const messageId = createId("msg") - const textPartId = createId("part") + const textPartId = createId("prt") const resolvedPrompt = resolvePastedPlaceholders(prompt, attachments) @@ -110,7 +110,6 @@ async function sendMessage( const requestParts: any[] = [ { - id: textPartId, type: "text" as const, text: resolvedPrompt, }, @@ -120,9 +119,8 @@ async function sendMessage( for (const att of attachments) { const source = att.source if (source.type === "file") { - const partId = createId("part") + const partId = createId("prt") requestParts.push({ - id: partId, type: "file" as const, url: att.url, mime: source.mime, @@ -148,9 +146,8 @@ async function sendMessage( continue } - const partId = createId("part") + const partId = createId("prt") requestParts.push({ - id: partId, type: "text" as const, text: value, }) @@ -184,7 +181,6 @@ async function sendMessage( }) const requestBody = { - messageID: messageId, parts: requestParts, ...(session.agent && { agent: session.agent }), ...(session.model.providerId && diff --git a/packages/ui/src/stores/session-events.ts b/packages/ui/src/stores/session-events.ts index 0d6ed470..710c7dab 100644 --- a/packages/ui/src/stores/session-events.ts +++ b/packages/ui/src/stores/session-events.ts @@ -240,19 +240,22 @@ function resolveMessageRole(info?: MessageInfo | null): MessageRole { return info?.role === "user" ? "user" : "assistant" } -function findPendingMessageId( +function findPendingSyntheticMessageId( store: InstanceMessageStore, sessionId: string, role: MessageRole, ): string | undefined { const messageIds = store.getSessionMessageIds(sessionId) - const lastId = messageIds[messageIds.length - 1] - if (!lastId) return undefined - const record = store.getMessage(lastId) - if (!record) return undefined - if (record.sessionId !== sessionId) return undefined - if (record.role !== role) return undefined - return record.status === "sending" ? record.id : undefined + for (const messageId of messageIds) { + const record = store.getMessage(messageId) + if (!record) continue + if (record.sessionId !== sessionId) continue + if (record.role !== role) continue + if (record.status !== "sending") continue + if (!record.isEphemeral) continue + return record.id + } + return undefined } function handleMessageUpdate(instanceId: string, event: MessageUpdateEvent | MessagePartUpdatedEvent): void { @@ -282,9 +285,9 @@ function handleMessageUpdate(instanceId: string, event: MessageUpdateEvent | Mes let record = store.getMessage(messageId) if (!record) { - const pendingId = findPendingMessageId(store, sessionId, role) + const pendingId = findPendingSyntheticMessageId(store, sessionId, role) if (pendingId && pendingId !== messageId) { - replaceMessageIdV2(instanceId, pendingId, messageId) + replaceMessageIdV2(instanceId, pendingId, messageId, { clearParts: role === "user" }) record = store.getMessage(messageId) } } @@ -345,9 +348,9 @@ function handleMessageUpdate(instanceId: string, event: MessageUpdateEvent | Mes let record = store.getMessage(messageId) if (!record) { - const pendingId = findPendingMessageId(store, sessionId, role) + const pendingId = findPendingSyntheticMessageId(store, sessionId, role) if (pendingId && pendingId !== messageId) { - replaceMessageIdV2(instanceId, pendingId, messageId) + replaceMessageIdV2(instanceId, pendingId, messageId, { clearParts: role === "user" }) record = store.getMessage(messageId) } }