Enable command queueing and fix message duplication issues

- Remove sending() state blocking to allow queueing multiple messages
- Add optimistic message creation with temp IDs for immediate UI feedback
- Implement QUEUED badge display matching TUI behavior (accent color, bold)
- Compute queued state: user message ID > last assistant message ID
- Clear prompt input immediately before async send for better UX
- Fix duplicate messages by properly finding and replacing temp messages
- Fix duplicate parts by clearing optimistic parts when real message arrives
- Fix state mutation bugs in message.part.updated handler (immutable updates)
- Fix state mutation bugs in message.updated handler (immutable updates)

Matches TUI implementation for consistent user experience across clients.
This commit is contained in:
Shantur Rathore
2025-10-24 16:38:42 +01:00
parent e3bc947195
commit 7be4248e20
5 changed files with 149 additions and 73 deletions

View File

@@ -47,18 +47,29 @@ export default function MessageStream(props: MessageStreamProps) {
const displayItems = createMemo(() => {
const items: DisplayItem[] = []
let lastAssistantMessageId = ""
for (let i = props.messages.length - 1; i >= 0; i--) {
if (props.messages[i].type === "assistant") {
lastAssistantMessageId = props.messages[i].id
break
}
}
for (const message of props.messages) {
const messageInfo = props.messagesInfo?.get(message.id)
const textParts = message.parts.filter((p) => p.type === "text" && !p.synthetic)
const toolParts = message.parts.filter((p) => p.type === "tool")
const reasoningParts = message.parts.filter((p) => p.type === "reasoning")
const isQueued = message.type === "user" && message.id > lastAssistantMessageId
if (textParts.length > 0 || reasoningParts.length > 0 || messageInfo?.error) {
items.push({
type: "message",
data: {
...message,
parts: [...textParts, ...reasoningParts],
isQueued,
},
messageInfo,
})
@@ -156,7 +167,7 @@ export default function MessageStream(props: MessageStreamProps) {
</div>
}
>
<MessageItem message={item.data} messageInfo={item.messageInfo} />
<MessageItem message={item.data} messageInfo={item.messageInfo} isQueued={item.data.isQueued} />
</Show>
)
}}