Skip to content

Commit 347b842

Browse files
committed
Accumulate message chunks before transform, store, and send
1 parent 297ecfd commit 347b842

File tree

5 files changed

+24
-25
lines changed

5 files changed

+24
-25
lines changed

js/chat/chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ class ChatContainer extends LightElement {
334334
const lastMessage = messages.lastElementChild as HTMLElement;
335335
if (!lastMessage) throw new Error("No messages found in the chat output");
336336
const content = lastMessage.getAttribute("content");
337-
lastMessage.setAttribute("content", content + message.content);
337+
lastMessage.setAttribute("content", message.content);
338338

339339
// Don't scroll to bottom if the user has scrolled up a bit
340340
if (

shiny/ui/_chat.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def __init__(
122122
self.on_error = on_error
123123

124124
# Chunked messages get accumulated (using this property) before changing state
125-
self._final_message = ""
125+
self._current_stream_message = ""
126126
self._current_stream_id: str | None = None
127127
self._pending_messages: list[PendingMessage] = []
128128

@@ -370,15 +370,20 @@ async def _append_message(
370370
self._pending_messages.append((message, chunk, stream_id))
371371
return
372372

373+
# Update current stream state
373374
self._current_stream_id = stream_id
374-
375375
if chunk == "end":
376376
self._current_stream_id = None
377377

378-
if chunk:
379-
msg = normalize_message_chunk(message)
380-
else:
378+
if not chunk:
381379
msg = normalize_message(message)
380+
else:
381+
msg = normalize_message_chunk(message)
382+
# Update the current stream message
383+
self._current_stream_message += msg["content"]
384+
msg["content"] = self._current_stream_message
385+
if chunk == "end":
386+
self._current_stream_message = ""
382387

383388
msg = await self._transform_message(msg)
384389
if msg is None:
@@ -471,11 +476,17 @@ async def _send_append_message(
471476
else:
472477
msg_type = "shiny-chat-append-message"
473478

479+
chunk_type = None
480+
if chunk == "start":
481+
chunk_type = "message_start"
482+
elif chunk == "end":
483+
chunk_type = "message_end"
484+
474485
msg = ClientMessage(
475486
content=message["content"],
476487
role=message["role"],
477488
content_type=message.get("content_type", "markdown"),
478-
chunk_type=message.get("chunk_type", None),
489+
chunk_type=chunk_type,
479490
)
480491

481492
# print(msg)
@@ -614,21 +625,11 @@ def _store_message(
614625
msg: StoredMessage = {
615626
**message,
616627
"token_count": None,
617-
"chunk_type": None,
618628
}
619629

620-
if chunk:
621-
self._final_message += msg["content"]
622-
if isinstance(chunk, str):
623-
msg["chunk_type"] = (
624-
"message_start" if chunk == "start" else "message_end"
625-
)
626-
# Don't count tokens or invalidate until the end of the chunk
627-
if chunk == "end":
628-
msg["content"] = self._final_message
629-
self._final_message = ""
630-
else:
631-
return msg
630+
# Don't actually store chunks until the end
631+
if chunk is True or chunk == "start":
632+
return msg
632633

633634
if self._tokenizer is not None:
634635
encoded = self._tokenizer.encode(msg["content"])

shiny/ui/_chat_types.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ class TransformedMessage(ChatMessage):
2424
class StoredMessage(TransformedMessage):
2525
# Number of tokens in the content
2626
token_count: int | None
27-
# For chunked messages
28-
chunk_type: Literal["message_start", "message_end"] | None
2927

3028

3129
# A message that can be sent to the client

shiny/www/shared/py-shiny/chat/chat.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

shiny/www/shared/py-shiny/chat/chat.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)