fix: handle both assistant and delta events without duplicates
This commit is contained in:
parent
6e6bb86bcd
commit
71cf8d2d62
1 changed files with 22 additions and 6 deletions
|
|
@ -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 = '';
|
||||||
|
|
|
||||||
Reference in a new issue