From 4a002c85d472d468d4112a2a8e69ec6c7515a171 Mon Sep 17 00:00:00 2001 From: Jason Tudisco Date: Fri, 6 Mar 2026 20:23:49 -0600 Subject: [PATCH] feat: add streaming AI responses with smooth token-by-token rendering Replaces batch AI responses with real-time SSE streaming from OpenRouter. Tokens are buffered client-side and drained via requestAnimationFrame for a smooth typing effect instead of choppy chunk dumps. Backend: - Rewrite openrouter service for SSE streaming with incremental tool call accumulation - Add AiStreamChunk/AiStreamEnd WebSocket event types - Stream content deltas to clients during all tool call rounds - Increase broadcast channel capacity (256 -> 4096) and handle Lagged errors gracefully Frontend: - Add StreamBuffer utility with adaptive rAF-based character draining - Show streaming message-bubble with blinking cursor during generation - Clean up buffer on room switch and final message replacement Co-Authored-By: Claude Opus 4.6 --- client/src/components/app.riot | 72 ++++++ client/src/components/chat-room.riot | 12 +- client/src/components/message-bubble.riot | 22 +- client/src/services/stream-buffer.js | 92 +++++++ server/src/handlers/ws.rs | 183 ++++++++------ server/src/main.rs | 2 +- server/src/models/mod.rs | 11 + server/src/services/openrouter.rs | 295 ++++++++++++++++------ 8 files changed, 533 insertions(+), 156 deletions(-) create mode 100644 client/src/services/stream-buffer.js diff --git a/client/src/components/app.riot b/client/src/components/app.riot index a2d344b..8d94548 100644 --- a/client/src/components/app.riot +++ b/client/src/components/app.riot @@ -26,6 +26,7 @@ ai-typing={state.aiTyping} ai-tool-status={state.aiToolStatus} typing-users={state.typingUsers} + streaming-message={state.streamingMessage} cb-send={sendMessage} cb-invite={() => update({ showInviteModal: true })} cb-delete-room={() => update({ showDeleteModal: true })} @@ -142,6 +143,7 @@