AI News HubLIVE
In-site rewrite4 min read

SvelteChatKit: Provider agnostic AI chat UI for OpenAI, Dify, n8n, and others

SvelteChatKit is a universal, provider-agnostic AI chat UI kit for SvelteKit that supports OpenAI, Ollama, Dify, and custom backends through a unified interface, featuring streaming, persistence, markdown rendering, and a zero-config demo mode.

SourceHacker News AIAuthor: kristofers32

Notifications You must be signed in to change notification settings

Fork 0

Star 1

BranchesTags

Open more actions menu

Folders and files

NameName

Last commit message

Last commit date

Latest commit

History

6 Commits

6 Commits

.claude

.claude

docs

docs

src

src

static

static

.env.example

.env.example

.gitignore

.gitignore

.prettierignore

.prettierignore

.prettierrc

.prettierrc

CONTRIBUTING.md

CONTRIBUTING.md

LICENSE

LICENSE

README.md

README.md

package-lock.json

package-lock.json

package.json

package.json

postcss.config.js

postcss.config.js

svelte.config.js

svelte.config.js

tailwind.config.js

tailwind.config.js

tsconfig.json

tsconfig.json

vite.config.ts

vite.config.ts

Repository files navigation

A universal, provider-agnostic AI chat UI kit for SvelteKit.

SvelteChatKit is a complete, streaming chat interface for SvelteKit 2 and Svelte 5 (runes) that talks to any LLM backend through one small interface. Swap between OpenAI-compatible APIs, Ollama, Dify, or your own endpoint by changing a config object — the UI, state management, markdown rendering, and persistence stay exactly the same. If your chat UI shouldn't be married to one vendor's API shape, this is the kit for you.

Features

Streaming responses — token-by-token rendering over SSE, NDJSON, or raw text streams, with a stop button that aborts cleanly mid-stream

Provider-agnostic — one ChatProvider interface; add a new backend without touching kit code

Persistence — conversation history survives reloads via localStorage (opt-in, SSR-safe)

Markdown + syntax highlighting — GFM rendering with highlight.js code blocks, sanitized with DOMPurify

Smart auto-scroll — follows the stream while you're near the bottom, never yanks the view when you scroll up, floating scroll-to-bottom pill

Error handling — typed ChatProviderError with actionable messages, dismissable inline error banner, per-message error states

Mobile responsive — usable at 375px, 16px inputs (no iOS zoom), auto-growing textarea

Dark mode — coherent light/dark styling via Tailwind dark: variants

TypeScript strict — fully typed public API

Zero-config demo mode — a built-in mock provider streams canned markdown responses with no API key, so npm run dev just works

Supported providers

Provider id Works with Transport Config

OpenAI-compatible openai OpenAI, OpenRouter, Groq, LM Studio, vLLM, llama.cpp, Azure-style gateways SSE (POST {baseUrl}/chat/completions) baseUrl, apiKey, model

Ollama ollama Local models via Ollama NDJSON (POST {baseUrl}/api/chat) baseUrl, model — browser use requires OLLAMA_ORIGINS

Dify dify Dify chat apps (conversation-based) SSE (POST {baseUrl}/chat-messages) baseUrl, apiKey

Custom endpoint custom Your own backend or server proxy Auto-detected: SSE, streamed text, or plain body baseUrl (full endpoint URL), headers

Mock mock Demo mode — no network calls — none

Quick start

git clone https://github.com/yourname/sveltechatkit.git cd sveltechatkit

npm install # or: pnpm install cp .env.example .env npm run dev # or: pnpm dev

Open the printed URL and start chatting — the demo runs on the mock provider out of the box, no keys required. Fill in .env to point it at a real backend. Node 20+ required.

Usage

Create a provider, hand it to a Chat instance, and render ChatWindow:

Chat exposes runes-reactive messages, status, error, and busy, plus send(), stop(), clear(), and setProvider() — so you can also build a fully custom UI on top of it.

A custom provider in ~20 lines

Any object implementing ChatProvider works. Register it once and it becomes available through the same factory as the built-ins:

import { ensureOk, registerProvider, sseStream } from '$lib'; import type { ChatMessage, ChatProvider, ProviderConfig, SendMessageOptions } from '$lib';

class MyBackendProvider implements ChatProvider { readonly id = 'my-backend'; readonly label = 'My Backend';

constructor(private config: ProviderConfig) {}

async *sendMessage(messages: ChatMessage[], options?: SendMessageOptions) { const response = await fetch(${this.config.baseUrl}/chat, { method: 'POST', headers: { 'Content-Type': 'application/json', ...this.config.headers }, body: JSON.stringify({ messages: messages.map(({ role, content }) => ({ role, content })) }), signal: options?.signal }); await ensureOk(response, this.id); for await (const data of sseStream(response)) { if (data === '[DONE]') return; yield JSON.parse(data).content as string; } } }

registerProvider('my-backend', (config) => new MyBackendProvider(config));

For a complete walkthrough — including a working Anthropic provider — see docs/adding-a-provider.md.

Configuration

The demo reads PUBLIC_* variables from .env (see .env.example). All are optional; with no .env at all the demo runs on the mock provider.

Variable Default Description

PUBLIC_DEFAULT_PROVIDER mock Provider selected on load: mock | openai | ollama | dify | custom

PUBLIC_OPENAI_BASE_URL https://api.openai.com/v1 Any OpenAI-compatible base URL

PUBLIC_OPENAI_API_KEY — API key sent as Authorization: Bearer …

PUBLIC_OPENAI_MODEL gpt-4o-mini Default model

PUBLIC_DIFY_BASE_URL https://api.dify.ai/v1 Dify API base URL

PUBLIC_DIFY_API_KEY — Dify app API key

PUBLIC_OLLAMA_BASE_URL http://localhost:11434 Ollama server URL

PUBLIC_OLLAMA_MODEL llama3.1 Default Ollama model

PUBLIC_CUSTOM_ENDPOINT — Full URL of your own chat endpoint

A note on keys: PUBLIC_* variables are embedded in the client bundle and visible to anyone using your site. They're fine for local development, but in production keep keys server-side: point the custom endpoint provider at a small proxy route that adds the Authorization header on the server.

Screenshots

The demo app running on the built-in mock provider — no API key required.

Light Dark

Architecture

┌──────────────────────────────────────────────────────┐ │ Components │ │ ChatWindow ─ MessageList ─ MessageBubble │ │ ChatInput ─ Markdown ─ TypingIndicator │ └──────────────────────────┬───────────────────────────┘ │ props ┌────────▼─────────┐ │ Chat (runes) │ messages · status · error │ send/stop/clear │ persistence · abort └────────┬─────────┘ │ sendMessage(history, { signal, model }) ┌───────────▼────────────┐ │ ChatProvider interface │ AsyncGenerator └───────────┬────────────┘ ┌─────────┬─────────┼──────────┬───────────┐ ▼ ▼ ▼ ▼ ▼ OpenAI- Ollama Dify Custom Mock compat. endpoint (no network) │ │ │ │ ▼ ▼ ▼ ▼ SSE NDJSON SSE SSE / text (upstream chat APIs)

Module Purpose

src/lib/chat/types.ts Core contracts: ChatMessage, ChatProvider, ProviderConfig, ChatProviderError

src/lib/chat/chat.svelte.ts Chat runes state class: send/stop/clear, streaming loop, persistence

src/lib/chat/providers/ Provider registry (registerProvider, createProvider) + five built-ins

src/lib/chat/stream.ts Transport helpers: sseStream, lineStream, textStream, ensureOk

src/lib/chat/config.ts defineChatKitConfig + env-driven defaultConfig

src/lib/chat/markdown.ts renderMarkdown: marked + highlight.js + DOMPurify

src/lib/chat/storage.ts SSR-safe localStorage history persistence

src/lib/components/ The six UI components

src/routes/ Demo app (provider switcher, connection settings, chat)

Roadmap

Auth support (session-scoped keys, token refresh hooks)

Vector DB / RAG integration helpers

Plugin system (message middleware, custom renderers)

More UI themes

File attachments

Function/tool-calling UI

Publish as an npm package

Contributing

Contributions are welcome — bug reports, new providers, UI polish, docs. Please read CONTRIBUTING.md for setup, code style, and PR guidelines. Adding a backend? Start with docs/adding-a-provider.md.

License

MIT — use it, fork it, ship it.

About

No description, website, or topics provided.

Resources

Readme

License

MIT license

Contributing

Contributing

Uh oh!

There was an error while loading. Please reload this page.

Activity

Stars

1 star

Watchers

0 watching

Forks

0 forks

Report repository

Releases

No releases published

Packages 0

Uh oh!

There was an error while loading. Please reload this page.

Contributors

Uh oh!

There was an error while loading. Please reload this page.

Languages

TypeScript 62.2%

Svelte 33.0%

CSS 2.5%

JavaScript 1.6%

HTML 0.7%