The AI workspace combines streamed model responses with realtime dashboard updates. Streaming handles the assistant response itself, while realtime keeps the sidebar, unread state, active streams, and other browser tabs in sync.
Stream Surfaces
The main chat session lives under src/features/ai/chat/components/chat-session.
Important stream files include:
src/features/ai/chat/components/chat-session/chat-session.tsxfor the activeuseChatsession.src/features/ai/chat/hooks/use-chat-send-flow.tsfor submit behavior.src/features/ai/chat/hooks/use-chat-resume-flow.tsfor reconnecting to an active stream.src/features/ai/chat/hooks/use-chat-stream-tracking.tsfor local stream state.src/features/ai/chat/hooks/use-mutate-stop-chat-stream.tsfor stop actions.src/features/ai/chat/utils/resumable-chat-stream.server.tsfor server side resumable stream handling.src/features/ai/chat/utils/chat-stream-finish.server.tsfor final message persistence.src/features/ai/chat/utils/chat-stream-stop.server.tsfor stopped stream persistence.
The UI throttles stream updates so the chat feels responsive without forcing too many renders.
export const CHAT_STREAM_UI_THROTTLE_MS = 16Stream Lifecycle
The normal stream flow is:
- The user sends a message or regenerates an assistant response.
- The request is validated and connected to the selected chat, project, and model.
- The server starts a resumable stream.
- The client renders partial assistant output as it arrives.
- On finish, the final assistant message and metadata are saved.
- If the user stops the stream, the stopped state is saved and the UI keeps the partial response.
- If the page refreshes while a stream is active, the client can reconnect and continue from the active stream state.
Use the stream utilities when changing stop, retry, regenerate, resume, or finish behavior. Keep database writes on the server side and keep the chat session UI focused on rendering and user actions.
Realtime Updates
Realtime events are used for sidebar and dashboard state, not for replacing the model stream.
Important realtime files include:
src/features/ai/chat/constants/chat-realtime.constants.tsfor event names.src/features/ai/chat/utils/chat-realtime.server.tsfor publishing events.src/features/ai/chat/components/chat-realtime-events-bridge.tsxfor mounting realtime behavior in the dashboard.src/features/ai/chat/hooks/use-chat-realtime-events.tsfor receiving events in the browser.src/features/ai/chat/utils/chat-realtime-channel.utils.tsfor channel names.
Realtime updates power:
- Sidebar chat creation and title updates.
- Project chat updates.
- Active stream indicators.
- Unseen chat indicators.
- Multi tab and multi device updates.
The request schema includes sourceClientId so the browser that caused an event can ignore its own duplicate realtime update.
export const chatRequestSchema = z.object({
chatId: z.string().min(1),
sourceClientId: z.string().min(1).optional(),
})User Controls
The workspace exposes the controls users expect in a serious AI product:
- Stop a running response.
- Retry a failed message.
- Regenerate the last assistant response.
- Resume an active stream after refresh.
- Keep chat history, titles, and sidebar state current in realtime.
When changing these flows, verify the normal send path, regenerate path, stop path, and refresh during active stream path.
Where To Customize
Use these files first:
src/features/ai/chat/constants/chat-stream.constants.tsfor stream timing and stream state constants.src/features/ai/chat/utils/resumable-chat-stream.server.tsfor resumable stream behavior.src/features/ai/chat/utils/chat-stream-stop.server.tsfor stopped responses.src/features/ai/chat/utils/chat-stream-finish.server.tsfor final persistence.src/features/ai/chat/constants/chat-realtime.constants.tsfor event names.src/features/ai/chat/hooks/use-chat-realtime-events.tsfor browser realtime behavior.
Keep stream status labels human readable. Users should see clear actions such as stopping, retrying, or reconnecting, not internal event names.