mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 09:13:14 +00:00
fix: show submitted user message immediately in web chat (#1478)
* fix: render submitted user message immediately in web chat Insert the optimistic prompt into local pendingPrompts state on submit so the user's message appears right away instead of only after the agent responds and thread.messages refetches. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> * fix: keep queued user prompts in submission order Offset each pending prompt's insertAt by the number of prompts already pending so multiple follow-ups queued before the backend echoes them don't collide at the same splice index and render out of order. Applies to both the local state and persisted sessionStorage paths. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> * fix: roll back optimistic message on send failure, single insertAt source --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
parent
722279e277
commit
16eb15bab3
2 changed files with 45 additions and 27 deletions
|
|
@ -1,13 +1,14 @@
|
|||
import { useEffect, useMemo, useState } from "react"
|
||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||
import { useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
import type { PendingPrompt } from "@/lib/agents/pendingPrompts"
|
||||
import type { AgentThread, Message } from "@/lib/agents/types"
|
||||
import type { AgentThread, ImageChunk, Message } from "@/lib/agents/types"
|
||||
import type { ModelSelection } from "@/lib/agents/useModelOptions"
|
||||
import { AgentPromptBar } from "@/components/agents/AgentPromptBar"
|
||||
import { MessageView } from "@/components/agents/ported"
|
||||
import { agentThreadKeys, useSendAgentMessage } from "@/lib/agents/queries"
|
||||
import {
|
||||
addPendingPrompt,
|
||||
dropPendingPrompts,
|
||||
getPendingPrompts,
|
||||
} from "@/lib/agents/pendingPrompts"
|
||||
|
|
@ -93,6 +94,46 @@ export function AgentThreadView({ thread }: AgentThreadViewProps) {
|
|||
)
|
||||
}, [queryClient, thread])
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(content: string, images: Array<ImageChunk>) => {
|
||||
const entry: PendingPrompt = {
|
||||
prompt: content,
|
||||
insertAt: thread.messages.length + pendingPrompts.length,
|
||||
images,
|
||||
}
|
||||
addPendingPrompt(thread.id, entry.prompt, entry.insertAt, entry.images)
|
||||
setPendingPrompts((prev) => [...prev, entry])
|
||||
sendMessage.mutate(
|
||||
{
|
||||
content,
|
||||
images,
|
||||
model_id: activeSelection?.modelId ?? null,
|
||||
effort: activeSelection?.effort ?? null,
|
||||
},
|
||||
{
|
||||
onError: () => {
|
||||
setPendingPrompts(
|
||||
dropPendingPrompts(
|
||||
thread.id,
|
||||
(p) =>
|
||||
p.insertAt === entry.insertAt &&
|
||||
p.prompt === entry.prompt &&
|
||||
pendingImageKey(p) === pendingImageKey(entry)
|
||||
)
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
[
|
||||
sendMessage,
|
||||
thread.id,
|
||||
thread.messages.length,
|
||||
pendingPrompts.length,
|
||||
activeSelection,
|
||||
]
|
||||
)
|
||||
|
||||
const displayMessages = useMemo<Array<Message>>(() => {
|
||||
if (pendingPrompts.length === 0) return thread.messages
|
||||
const baseTimestamp = new Date().toISOString()
|
||||
|
|
@ -136,14 +177,7 @@ export function AgentThreadView({ thread }: AgentThreadViewProps) {
|
|||
compact
|
||||
busy={isStreaming}
|
||||
disabled={sendMessage.isPending}
|
||||
onSubmit={(content, images) =>
|
||||
sendMessage.mutate({
|
||||
content,
|
||||
images,
|
||||
model_id: activeSelection?.modelId ?? null,
|
||||
effort: activeSelection?.effort ?? null,
|
||||
})
|
||||
}
|
||||
onSubmit={handleSubmit}
|
||||
models={models}
|
||||
selection={activeSelection}
|
||||
onSelectionChange={setSelection}
|
||||
|
|
@ -162,14 +196,7 @@ export function AgentThreadView({ thread }: AgentThreadViewProps) {
|
|||
compact
|
||||
busy={isStreaming}
|
||||
disabled={sendMessage.isPending}
|
||||
onSubmit={(content, images) =>
|
||||
sendMessage.mutate({
|
||||
content,
|
||||
images,
|
||||
model_id: activeSelection?.modelId ?? null,
|
||||
effort: activeSelection?.effort ?? null,
|
||||
})
|
||||
}
|
||||
onSubmit={handleSubmit}
|
||||
models={models}
|
||||
selection={activeSelection}
|
||||
onSelectionChange={setSelection}
|
||||
|
|
|
|||
|
|
@ -144,15 +144,6 @@ export function useSendAgentMessage(threadId: string) {
|
|||
model_id: vars.model_id,
|
||||
effort: vars.effort,
|
||||
}),
|
||||
onMutate: (vars) => {
|
||||
const cached = queryClient.getQueryData<{ messages?: Array<unknown> }>(
|
||||
agentThreadKeys.detail(threadId)
|
||||
)
|
||||
const insertAt = Array.isArray(cached?.messages)
|
||||
? cached.messages.length
|
||||
: 0
|
||||
addPendingPrompt(threadId, vars.content, insertAt, vars.images)
|
||||
},
|
||||
onSuccess: (thread) => {
|
||||
queryClient.setQueryData(
|
||||
agentThreadKeys.detail(threadId),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue