())
- setPasteCount(0)
- setImageCount(0)
-
- if (textareaRef) {
- textareaRef.style.height = "auto"
- }
} catch (error) {
console.error("Failed to send message:", error)
alert("Failed to send message: " + (error instanceof Error ? error.message : String(error)))
} finally {
- setSending(false)
textareaRef?.focus()
}
}
@@ -612,7 +610,7 @@ export default function PromptInput(props: PromptInputProps) {
textareaRef?.focus()
}
- const canSend = () => (prompt().trim().length > 0 || attachments().length > 0) && !sending() && !props.disabled
+ const canSend = () => (prompt().trim().length > 0 || attachments().length > 0) && !props.disabled
const instance = () => getActiveInstance()
@@ -720,16 +718,14 @@ export default function PromptInput(props: PromptInputProps) {
onPaste={handlePaste}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
- disabled={sending() || props.disabled}
+ disabled={props.disabled}
rows={1}
style={attachments().length > 0 ? { "padding-top": "8px" } : {}}
/>
diff --git a/src/index.css b/src/index.css
index a97f973a..3c49382e 100644
--- a/src/index.css
+++ b/src/index.css
@@ -189,9 +189,22 @@ body {
}
.message-content {
- display: flex;
- flex-direction: column;
- gap: 8px;
+ padding-top: 6px;
+ line-height: 1.6;
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+
+.message-queued-badge {
+ display: inline-block;
+ background-color: var(--accent-color);
+ color: white;
+ font-weight: bold;
+ padding: 4px 12px;
+ border-radius: 4px;
+ margin-bottom: 12px;
+ font-size: 12px;
+ letter-spacing: 0.5px;
}
.message-text {
diff --git a/src/stores/sessions.ts b/src/stores/sessions.ts
index 9c3572e1..89d2c6f6 100644
--- a/src/stores/sessions.ts
+++ b/src/stores/sessions.ts
@@ -487,34 +487,40 @@ function handleMessageUpdate(instanceId: string, event: any): void {
const part = event.properties?.part
if (!part) return
- const session = instanceSessions.get(part.sessionID)
- if (!session) return
-
- let message = session.messages.find((m) => m.id === part.messageID)
-
- if (!message) {
- message = {
- id: part.messageID,
- sessionId: part.sessionID,
- type: "assistant",
- parts: [part],
- timestamp: Date.now(),
- status: "streaming",
- }
- session.messages.push(message)
- } else {
- const partIndex = message.parts.findIndex((p: any) => p.id === part.id)
- if (partIndex === -1) {
- message.parts.push(part)
- } else {
- message.parts[partIndex] = part
- }
- }
-
setSessions((prev) => {
const next = new Map(prev)
const instanceSessions = new Map(prev.get(instanceId))
- instanceSessions.set(part.sessionID, { ...session })
+ const session = instanceSessions.get(part.sessionID)
+
+ if (!session) return prev
+
+ const messages = [...session.messages]
+ const messageIndex = messages.findIndex((m) => m.id === part.messageID)
+
+ if (messageIndex === -1) {
+ messages.push({
+ id: part.messageID,
+ sessionId: part.sessionID,
+ type: "assistant",
+ parts: [part],
+ timestamp: Date.now(),
+ status: "streaming",
+ })
+ } else {
+ const message = messages[messageIndex]
+ const parts = [...message.parts]
+ const partIndex = parts.findIndex((p: any) => p.id === part.id)
+
+ if (partIndex === -1) {
+ parts.push(part)
+ } else {
+ parts[partIndex] = part
+ }
+
+ messages[messageIndex] = { ...message, parts }
+ }
+
+ instanceSessions.set(part.sessionID, { ...session, messages })
next.set(instanceId, instanceSessions)
return next
})
@@ -522,36 +528,51 @@ function handleMessageUpdate(instanceId: string, event: any): void {
const info = event.properties?.info
if (!info) return
- const session = instanceSessions.get(info.sessionID)
- if (!session) return
-
- let message = session.messages.find((m) => m.id === info.id)
-
- if (!message) {
- message = {
- id: info.id,
- sessionId: info.sessionID,
- type: info.role === "user" ? "user" : "assistant",
- parts: [],
- timestamp: info.time?.created || Date.now(),
- status: "complete",
- }
- session.messages.push(message)
- } else {
- // Update existing message - replace temp message with real one
- message.id = info.id
- message.status = "complete"
- }
-
setSessions((prev) => {
const next = new Map(prev)
const instanceSessions = new Map(prev.get(instanceId))
- const updatedSession = instanceSessions.get(info.sessionID)
- if (updatedSession) {
- const messagesInfo = new Map(updatedSession.messagesInfo)
- messagesInfo.set(info.id, info)
- instanceSessions.set(info.sessionID, { ...updatedSession, messagesInfo })
+ const session = instanceSessions.get(info.sessionID)
+
+ if (!session) return prev
+
+ const messages = [...session.messages]
+ const messageIndex = messages.findIndex((m) => m.id === info.id)
+ const tempMessageIndex = messages.findIndex(
+ (m) =>
+ m.id.startsWith("temp-") &&
+ m.type === (info.role === "user" ? "user" : "assistant") &&
+ m.status === "sending",
+ )
+
+ if (messageIndex > -1) {
+ messages[messageIndex] = {
+ ...messages[messageIndex],
+ status: "complete",
+ }
+ } else if (tempMessageIndex > -1) {
+ messages[tempMessageIndex] = {
+ id: info.id,
+ sessionId: info.sessionID,
+ type: info.role === "user" ? "user" : "assistant",
+ parts: [],
+ timestamp: info.time?.created || Date.now(),
+ status: "complete",
+ }
+ } else {
+ messages.push({
+ id: info.id,
+ sessionId: info.sessionID,
+ type: info.role === "user" ? "user" : "assistant",
+ parts: [],
+ timestamp: info.time?.created || Date.now(),
+ status: "complete",
+ })
}
+
+ const messagesInfo = new Map(session.messagesInfo)
+ messagesInfo.set(info.id, info)
+
+ instanceSessions.set(info.sessionID, { ...session, messages, messagesInfo })
next.set(instanceId, instanceSessions)
return next
})
@@ -639,6 +660,36 @@ async function sendMessage(
throw new Error("Session not found")
}
+ const tempMessageId = `temp-${Date.now()}-${Math.random().toString(36).substring(7)}`
+
+ const textParts: any[] = []
+ textParts.push({
+ type: "text" as const,
+ text: prompt,
+ id: `${tempMessageId}-text`,
+ })
+
+ const optimisticMessage: Message = {
+ id: tempMessageId,
+ sessionId,
+ type: "user",
+ parts: textParts,
+ timestamp: Date.now(),
+ status: "sending",
+ }
+
+ setSessions((prev) => {
+ const next = new Map(prev)
+ const instanceSessions = new Map(prev.get(instanceId))
+ const session = instanceSessions.get(sessionId)
+ if (session) {
+ const messages = [...session.messages, optimisticMessage]
+ instanceSessions.set(sessionId, { ...session, messages })
+ next.set(instanceId, instanceSessions)
+ }
+ return next
+ })
+
const parts: any[] = [
{
type: "text" as const,