feat(web): add WebSocket transport for message event streaming with SSE fallback (#764)

* feat: add websocket message stream transport

* fix: avoid false missing session directories in sidebar

* fix: re-probe project root session directories

* refactor: use button group for message stream transport

* fix: resolve chat input hook dependency warning

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Yifan
2026-04-17 11:07:26 +03:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent fd8972a7d9
commit bee9d19f3a
26 changed files with 1515 additions and 163 deletions
+1
View File
@@ -569,6 +569,7 @@ export interface SettingsPayload {
showExpandedBashTools?: boolean;
showExpandedEditTools?: boolean;
chatRenderMode?: 'sorted' | 'live';
messageStreamTransport?: 'auto' | 'ws' | 'sse';
activityRenderMode?: 'collapsed' | 'summary';
mermaidRenderingMode?: 'svg' | 'ascii';
fontSize?: number;
+1
View File
@@ -125,6 +125,7 @@ export type DesktopSettings = {
timeFormatPreference?: 'auto' | '12h' | '24h';
weekStartPreference?: 'auto' | 'sunday' | 'monday';
chatRenderMode?: 'sorted' | 'live';
messageStreamTransport?: 'auto' | 'ws' | 'sse';
activityRenderMode?: 'collapsed' | 'summary';
mermaidRenderingMode?: 'svg' | 'ascii';
userMessageRenderingMode?: 'markdown' | 'plain';
+13
View File
@@ -297,6 +297,9 @@ const getRuntimeSettingsAPI = () => getRegisteredRuntimeAPIs()?.settings ?? null
const applyDesktopUiPreferences = (settings: DesktopSettings) => {
const store = useUIStore.getState();
const configStore = typeof window !== 'undefined'
? window.__zustand_config_store__?.getState?.() ?? null
: null;
const queueStore = useMessageQueueStore.getState();
if (typeof settings.showReasoningTraces === 'boolean' && settings.showReasoningTraces !== store.showReasoningTraces) {
@@ -407,6 +410,12 @@ const applyDesktopUiPreferences = (settings: DesktopSettings) => {
store.setUserMessageRenderingMode(settings.userMessageRenderingMode);
}
}
if (typeof settings.messageStreamTransport === 'string'
&& (settings.messageStreamTransport === 'auto' || settings.messageStreamTransport === 'ws' || settings.messageStreamTransport === 'sse')) {
if (configStore && settings.messageStreamTransport !== configStore.settingsMessageStreamTransport) {
configStore.setSettingsMessageStreamTransport(settings.messageStreamTransport);
}
}
if (typeof settings.stickyUserHeader === 'boolean' && settings.stickyUserHeader !== store.stickyUserHeader) {
store.setStickyUserHeader(settings.stickyUserHeader);
}
@@ -804,6 +813,10 @@ const sanitizeWebSettings = (payload: unknown): DesktopSettings | null => {
&& (candidate.chatRenderMode === 'sorted' || candidate.chatRenderMode === 'live')) {
result.chatRenderMode = candidate.chatRenderMode;
}
if (typeof candidate.messageStreamTransport === 'string'
&& (candidate.messageStreamTransport === 'auto' || candidate.messageStreamTransport === 'ws' || candidate.messageStreamTransport === 'sse')) {
result.messageStreamTransport = candidate.messageStreamTransport;
}
if (typeof candidate.activityRenderMode === 'string'
&& (candidate.activityRenderMode === 'collapsed' || candidate.activityRenderMode === 'summary')) {
result.activityRenderMode = candidate.activityRenderMode;