Skip to main content
Urbicon UI
← Back to Recipes

AI Chat

A full streaming chat surface — Chat shell + ChatMessageList + PromptInput — wired to a SvelteKit SSE endpoint that relays a Claude/LLM stream. Client reads the response as a ReadableStream (POST body, not EventSource), appends tokens in place to the last assistant message, and stops mid-stream via an AbortController.

Chat ChatMessageList PromptInput

Live Preview

This preview replays canned answers on a timer — no network — so it is reproducible offline. The code below streams from a real SSE endpoint, but drives the same surface and the same append/abort state machine. Send a message, then scroll up mid-stream or press Stop.

AI Assistant idle

Start the conversation

Send a message to watch a reply stream in.

Features

  • Chat shell with pinned header, scrollable log, and pinned composer (min-h-0 chain, full height)
  • ChatMessageList's stick-to-bottom engine: follows tokens at the bottom, breaks on upward scroll
  • PromptInput composer with a send button that flips to Stop while a response streams
  • SvelteKit +server.ts POST endpoint relaying an Anthropic stream as text/event-stream
  • Client fetch + ReadableStream reader (POST body needed → not EventSource)
  • In-place token append to the last assistant message (never mutate the array element)
  • AbortController Stop → status "aborted"; onRegenerate / onRetry re-run the last turn
  • Streaming lifecycle: streaming → complete / error / aborted

Server — the SSE endpoint

A plain SvelteKit +server.ts that relays the model stream as text/event-stream. (The @urbicon-ui/auth package ships createStreamHandler, but that is a notification SSE fan-out — GET-only, backed by an SSEManager — not an LLM chat relay, which needs a POST body. Write the endpoint directly, as here.)

src/routes/api/chat/+server.ts

Loading...
Loading syntax highlighting...

Client — the chat page

src/routes/chat/+page.svelte

Loading...
Loading syntax highlighting...