fix: handle both assistant and delta events without duplicates

This commit is contained in:
Zac Gaetano 2026-04-05 11:55:24 -04:00
parent 6e6bb86bcd
commit 71cf8d2d62

View file

@ -171,9 +171,9 @@ const App = () => {
} }
// Claude stream-json events // Claude stream-json events
// NOTE: We intentionally skip the 'assistant' event type. // We handle BOTH content_block_delta (streaming) and assistant (full message).
// It contains the full message text that was ALREADY streamed via // Short responses may arrive as assistant-only without any deltas.
// content_block_delta events, so handling it would create a duplicate bubble. // To prevent duplicates: assistant events only render if no deltas were received.
if (type === 'content_block_delta') { if (type === 'content_block_delta') {
const delta = data.delta; const delta = data.delta;
@ -184,14 +184,30 @@ const App = () => {
} }
if (type === 'content_block_stop') { if (type === 'content_block_stop') {
// Block done, finalize
if (pendingAssistantRef.current) { if (pendingAssistantRef.current) {
upsertStreamingMessage(pendingAssistantRef.current, false); upsertStreamingMessage(pendingAssistantRef.current, false);
} }
} }
if (type === 'assistant') {
// Full assistant message only use if we didn't get streaming deltas
if (!pendingAssistantRef.current) {
const content = data.message?.content;
let text = '';
if (Array.isArray(content)) {
text = content.filter(b => b.type === 'text').map(b => b.text).join('');
} else if (typeof content === 'string') {
text = content;
}
if (text) {
pendingAssistantRef.current = text;
upsertStreamingMessage(text, false);
}
}
// If deltas already built the text, skip no duplicate
}
if (type === 'result') { if (type === 'result') {
// Turn complete
const sub = data.subtype; const sub = data.subtype;
if (sub === 'success' || sub === 'error_max_turns') { if (sub === 'success' || sub === 'error_max_turns') {
if (pendingAssistantRef.current) { if (pendingAssistantRef.current) {
@ -200,7 +216,7 @@ const App = () => {
} }
if (data.session_id) setClaudeSessionId(data.session_id); if (data.session_id) setClaudeSessionId(data.session_id);
setChatWaiting(false); setChatWaiting(false);
fetchChatSessions(); // refresh session list fetchChatSessions();
} }
if (sub === 'error' || sub === 'error_during_execution') { if (sub === 'error' || sub === 'error_during_execution') {
pendingAssistantRef.current = ''; pendingAssistantRef.current = '';