Embeddable chat widget for EDDI — the open-source multi-agent orchestration middleware for conversational AI.
EDDI Chat UI is a standalone, themeable React chat widget that connects to any EDDI agent. It ships inside the EDDI Docker image and can also be embedded as an <iframe> in any web page. Supports SSE streaming, rich Markdown, LaTeX math, code highlighting, quick replies, and full conversation control — all configurable via URL parameters or a typed config object.
🌐 Website: eddi.labs.ai · 📖 Docs: docs.labs.ai · 🐳 Docker: hub.docker.com/r/labsai/eddi
- ✨ Features
- 🏁 Quick Start
- 🔗 URL Patterns
- ⚙️ Configuration
- 📦 Embedding
- 🏗️ Development
- 🧰 Tech Stack
- 📁 Project Structure
- 🔌 Backend Integration
- 🔗 Related
- 📜 License
- 💬 Rich Markdown — Tables, code blocks, bold/italic, links, lists, and raw HTML
- 🌊 SSE Streaming — Real-time token-by-token agent responses with thinking indicator
- 🧮 LaTeX Math — KaTeX rendering for mathematical expressions (
$inline$and$$block$$) - 🎨 Syntax Highlighting — Code blocks with language-aware highlighting via
rehype-highlight - 🌗 Dark / Light Themes — Toggle via UI button, URL parameter, or system preference
- ⚡ Quick Replies — Pill buttons for suggested responses returned by the agent
- ↩️ Undo / Redo — Step through conversation history with backend state sync
- 🔒 Password Fields — Masked input support when agents request sensitive data
- 🔧 Fully Configurable — Every feature togglable via URL query parameters or typed
ChatConfig - 📱 Responsive — Mobile-first design with adaptive breakpoints
- 🎭 Demo Mode — Full showcase without a running backend (
/chat/demo/showcase) - 🏷️ Agent Name Display — Auto-fetches and shows the agent's display name from the backend
The easiest way to use EDDI Chat UI is via the main EDDI project:
# One-command installer (includes Chat UI)
curl -fsSL https://raw.githubusercontent.com/labsai/EDDI/main/install.sh | bashThen open http://localhost:7070/chat.html.
See the EDDI README for full setup instructions.
# Prerequisites: Node.js ≥ 20, EDDI backend on localhost:7070
npm install
npm run dev # Vite dev server on http://localhost:5174The Vite dev proxy forwards API calls to the EDDI backend. If no backend is available, navigate to /chat/demo/showcase for the built-in demo mode.
| URL | Description |
|---|---|
/chat/:environment/:agentId |
Connect to a specific agent |
/chat/:environment/:agentId/:userId |
Connect with explicit user ID |
/chat/demo/showcase |
Demo mode with mock data (no backend) |
/chat/managed/:intent/:userId |
Managed agent mode (intent-based routing) |
All features can be toggled via URL query parameters — ideal for iframe embedding:
| Parameter | Example | Effect |
|---|---|---|
theme |
?theme=light |
Set initial theme (dark/light) |
title |
?title=My%20Agent |
Override header title |
hideUndo |
?hideUndo=true |
Hide undo button |
hideRedo |
?hideRedo=true |
Hide redo button |
hideNewConversation |
?hideNewConversation=true |
Hide restart button |
hideLogo |
?hideLogo=true |
Show text title instead of logo |
hideQuickReplies |
?hideQuickReplies=true |
Hide quick reply buttons |
Programmatic configuration (ChatConfig)
When integrating directly (not via iframe), you can pass a typed ChatConfig object:
interface ChatConfig {
apiBaseUrl?: string; // Default: window.location.origin
theme?: "dark" | "light" | "system";
accentColor?: string; // CSS value, default: "#113B92"
showLogo?: boolean; // Default: true
logoUrl?: string; // Default: /img/logo_eddi.png
title?: string; // Default: "EDDI"
placeholder?: string; // Default: "Type a message..."
enableStreaming?: boolean; // Default: true
enableQuickReplies?: boolean; // Default: true
enableMarkdown?: boolean; // Default: true
enableMath?: boolean; // Default: true
enableCodeHighlight?: boolean;// Default: true
enableUndo?: boolean; // Default: true
enableRedo?: boolean; // Default: true
enableNewConversation?: boolean; // Default: true
showAgentName?: boolean; // Default: true
}The chat UI can be embedded in any HTML page via iframe:
<iframe
src="https://your-eddi-server/chat/production/your-agent-id?hideNewConversation=true&theme=dark"
style="width: 400px; height: 600px; border: none; border-radius: 12px;"
></iframe>Combine query parameters to create a minimal, focused chat experience:
?hideUndo=true&hideRedo=true&hideNewConversation=true&hideLogo=true&title=Support%20Agent&theme=light
npm run dev # Dev server (port 5174) with proxy to EDDI backend
npm run build # Production build
npm run test # Run tests (46 Vitest unit/component tests)
npm run typecheck # TypeScript type checking (tsc --noEmit)All styles use vanilla CSS with BEM naming and CSS custom properties (design tokens) for theming:
.chat-header__logo /* Block__Element */
.message--user /* Block--Modifier */Dark/light themes are controlled by [data-theme] attribute — no runtime style injection.
- Context +
useReducerviaChatProvider→useChatState()/useChatDispatch() - No external state libraries (no Redux, no Zustand)
- Vitest + React Testing Library + jsdom
- Wrap components in
<ChatProvider>for tests window.matchMediamocked intest-setup.ts
| Layer | Technology |
|---|---|
| Build | Vite 6 |
| UI | React 19 + TypeScript 5.7 (strict) |
| Styling | Vanilla CSS with CSS custom properties (BEM naming) |
| Markdown | react-markdown 9 + remark-gfm + remark-math |
| Math | KaTeX 0.16 |
| Code | rehype-highlight |
| Routing | React Router v7 |
| Streaming | Native fetch + ReadableStream (SSE via AsyncGenerator) |
| Tests | Vitest 3 + React Testing Library |
src/
├── api/ # API layer (fetch + SSE streaming)
│ ├── chat-api.ts # Real EDDI backend API
│ └── demo-api.ts # Mock API for demo mode
├── components/ # React components
│ ├── ChatWidget.tsx # Main orchestrator (lifecycle, SSE, query params)
│ ├── ChatHeader.tsx # Logo/title, undo/redo, theme toggle, new conversation
│ ├── MessageBubble.tsx # Message rendering with Markdown + math + code
│ ├── ChatInput.tsx # Auto-grow textarea, Enter/Shift+Enter
│ ├── QuickReplies.tsx # Suggested reply pill buttons
│ ├── Indicators.tsx # Typing (dots) + Thinking (brain) indicators
│ ├── SecretInput.tsx # Masked password input for secret values
│ └── ScrollToBottom.tsx # Floating scroll button
├── hooks/
│ └── useTheme.ts # Dark/light/system theme with localStorage
├── store/
│ └── chat-store.tsx # Context + useReducer state management
├── styles/
│ ├── variables.css # CSS custom properties (dark/light design tokens)
│ └── chat.css # Component styles (BEM naming)
└── types.ts # Shared TypeScript types
The production build is deployed into the EDDI Quarkus backend at:
EDDI/src/main/resources/META-INF/resources/
This makes the chat UI available at http://your-eddi-server/chat.html — served directly by Quarkus with no separate web server required.
- EDDI — Backend engine (Java 25, Quarkus)
- EDDI Manager — Admin dashboard (React 19)
- quarkus-eddi — Quarkus SDK
Part of the EDDI project — Apache 2.0.