Stage 374: PR #2431 — fix(chat): render pending assistant placeholder before /api/chat/start returns by @Michaelyklam (fixes #2429)
Co-authored-by: Michael Lam <michael@example.local>
This commit is contained in:
1 parent
13265b7085
commit
a33cd4195b
3 files changed
+25
-4
No files matched your search
+1
-1
@@ -273,7 +273,7 @@ async function send(){
|
||||
const userMsg={role:'user',content:displayText,attachments:uploaded.length?uploadedNames:undefined,_ts:Date.now()/1000};
|
||||
S.toolCalls=[]; // clear tool calls from previous turn
|
||||
clearLiveToolCards(); // clear any leftover live cards from last turn
|
||||
S.messages.push(userMsg);renderMessages();appendThinking();setBusy(true);
|
||||
S.messages.push(userMsg);renderMessages();appendThinking('',{pending:true});setBusy(true);
|
||||
// First optimistic pass: make the local user turn visible before /api/chat/start
|
||||
// can save pending state on the server.
|
||||
if(typeof upsertActiveSessionForLocalTurn==='function'){
|
||||
|
||||
+3
-2
@@ -7033,11 +7033,12 @@ function finalizeThinkingCard(){
|
||||
_syncToolCallGroupSummary(group);
|
||||
}
|
||||
}
|
||||
function appendThinking(text=''){
|
||||
function appendThinking(text='', options){
|
||||
// Guard: ignore if session was switched during an async SSE stream.
|
||||
// The old stream's reasoning events can still fire after switch;
|
||||
// without this check they would pollute the new session's DOM.
|
||||
if(!S.session||!S.activeStreamId) return;
|
||||
const allowPendingPlaceholder=!!(options&&options.pending===true);
|
||||
if(!S.session||(!S.activeStreamId&&!allowPendingPlaceholder)) return;
|
||||
$('emptyState').style.display='none';
|
||||
let turn=$('liveAssistantTurn');
|
||||
if(!turn){
|
||||
|
||||
@@ -16,7 +16,7 @@ class TestSidebarFirstTurnVisibility:
|
||||
"send() must optimistically upsert the active session into the sidebar "
|
||||
"as soon as the local user message is pushed."
|
||||
)
|
||||
push_idx = src.index("S.messages.push(userMsg);renderMessages();appendThinking();setBusy(true);")
|
||||
push_idx = src.index("S.messages.push(userMsg);renderMessages();appendThinking('',{pending:true});setBusy(true);")
|
||||
helper_idx = src.index("upsertActiveSessionForLocalTurn", push_idx)
|
||||
start_idx = src.index("api('/api/chat/start'", push_idx)
|
||||
assert helper_idx < start_idx, (
|
||||
@@ -29,6 +29,26 @@ class TestSidebarFirstTurnVisibility:
|
||||
"that race can overwrite the optimistic first-turn row with an empty list."
|
||||
)
|
||||
|
||||
def test_messages_send_renders_pending_assistant_placeholder_before_chat_start(self):
|
||||
messages = read("static/messages.js")
|
||||
ui = read("static/ui.js")
|
||||
send_start = messages.index("async function send()")
|
||||
push_idx = messages.index("appendThinking('',{pending:true})", send_start)
|
||||
start_idx = messages.index("api('/api/chat/start'", send_start)
|
||||
assert push_idx < start_idx, (
|
||||
"send() should render an assistant-side pending placeholder before "
|
||||
"/api/chat/start or the first SSE event returns."
|
||||
)
|
||||
append_start = ui.index("function appendThinking(text='', options)")
|
||||
append_end = ui.index("function updateThinking", append_start)
|
||||
append_body = ui[append_start:append_end]
|
||||
assert "allowPendingPlaceholder" in append_body
|
||||
assert "options.pending===true" in append_body.replace(" ", ""), (
|
||||
"appendThinking() must allow the explicit pre-stream placeholder path "
|
||||
"without weakening the stale-stream guard for ordinary SSE updates."
|
||||
)
|
||||
assert "(!S.activeStreamId&&!allowPendingPlaceholder)" in append_body.replace(" ", "")
|
||||
|
||||
def test_sessions_js_has_local_turn_upsert_helper(self):
|
||||
src = read("static/sessions.js")
|
||||
assert "function upsertActiveSessionForLocalTurn" in src
|
||||
|
||||
Reference in new issue
Block a user