UI SDK
Ship AI chat UI in minutes
The Telygent UI SDK is a collection of accessible, customizable components designed to bridge the gap between your backend SDK and a polished user experience. It follows the shadcn/ui philosophy: it doesn't just install a library; it grafts the source code into your project so you have total control over the styling and behavior.
Installation & Setup
Initialize your project and pull in the core chat components using the CLI. This will scaffold the necessary providers, hooks, and UI elements into your components/ai folder.
1# Initialize the UI registry
2npx telygent-ui setup
3
4# OPTIONAL: Add the chat interface components
5npx telygent-ui add chat-interfaceAdapter pattern
To keep the UI framework-agnostic, the ChatInterface uses a Frontend Adapter. This allows you to connect the UI to any backend endpoint whether you are using the Telygent Node.js SDK, a custom Python backend, or a serverless function.
Core responsibilities:
sendMessageStream
Use this for a premium user experience. As the AI "thinks" and types, the UI SDK renders fragments of text and status updates in real-time. This reduces "perceived latency" significantly for long-running analytical queries.
Instead of a standard function, you provide an AsyncIterable viasendMessageStream. The UI SDK iterates over the stream events.
sendMessage
Use this if you prefer a simpler backend implementation or if your AI responses are typically very short. The UI will show a "loading" state until the entire response is ready.
The adapter waits for a single Promise to resolve. Once received, the UI renders the full markdown content and any associated visualizations at once.
getHistory
Standard setup
1import {ChatProvider, type SendMessageInput, type SendMessageResult, type ChatMessage} from "@/components/ai/ChatProvider";
2import {ChatInterface} from "@/components/ai/ChatInterface";
3
4const adapter = {
5 async sendMessage({message, conversationId}: SendMessageInput): Promise<SendMessageResult> {
6 const response = await api.send({message, conversationId});
7 return {
8 conversationId: response.conversationId,
9 message: {
10 role: "assistant",
11 content: response.content,
12 createdAt: new Date(),
13 visualizations: response.visualizations,
14 },
15 };
16 },
17 async getHistory(conversationId: string): Promise<ChatMessage[]> {
18 const history = await api.history(conversationId);
19 return history.messages.map((item) => ({
20 role: item.role === "assistant" ? "assistant" : "user",
21 content: item.content,
22 createdAt: new Date(item.timestamp),
23 visualizations: item.visualizations ?? [],
24 }));
25 },
26};
27
28export default function Page() {
29 return (
30 <ChatProvider adapter={adapter}>
31 <ChatInterface conversationId="conv_123" aiName="Telygent" />
32 </ChatProvider>
33 );
34}Streaming setup
1 import {
2 ChatProvider,
3 type SendMessageInput,
4 type ChatStreamEvent,
5 type ChatMessage,
6 } from "@/components/ai/ChatProvider";
7 import {ChatInterface} from "@/components/ai/ChatInterface";
8
9 async function* streamChat(input: SendMessageInput): AsyncIterable<ChatStreamEvent> {
10 const response = await fetch("/api/chat/stream", {
11 method: "POST",
12 headers: {"Content-Type": "application/json"},
13 body: JSON.stringify({
14 question: input.message,
15 conversationId: input.conversationId,
16 }),
17 });
18
19 const reader = response.body!.getReader();
20 const decoder = new TextDecoder();
21 let buffer = "";
22
23 while (true) {
24 const {value, done} = await reader.read();
25 if (done) break;
26
27 buffer += decoder.decode(value, {stream: true});
28 const lines = buffer.split("\n\n");
29 buffer = lines.pop() ?? "";
30
31 for (const line of lines) {
32 if (!line.startsWith("data: ")) continue;
33 const payload = JSON.parse(line.replace("data: ", "")) as ChatStreamEvent;
34 yield payload;
35 }
36 }
37 }
38
39 const adapter = {
40 sendMessageStream: streamChat,
41 async getHistory(conversationId: string): Promise<ChatMessage[]> {
42 const history = await api.history(conversationId);
43 return history.messages.map((item) => ({
44 role: item.role === "assistant" ? "assistant" : "user",
45 content: item.content,
46 createdAt: new Date(item.timestamp),
47 visualizations: item.visualizations ?? [],
48 }));
49 },
50 };
51
52 export default function Page() {
53 return (
54 <ChatProvider adapter={adapter}>
55 <ChatInterface conversationId="conv_123" aiName="Telygent" />
56 </ChatProvider>
57 );
58 }Adapter fields
conversationId
A unique identifier for your current conversation and to maintain context.
aiName
OptionalA brand or user friendly name you will like the AI to respond as
logo
Optionaldescription
OptionaldefaultPrompts
OptionalPlaceholder
OptionalStyling & Markdown Rendering
The Telygent UI SDK uses a custom CSS manifest (ai-mdx.css) to handle the typography and layout of AI-generated content. Without this file, standard HTML elements (like <table> or <ul>) may appear unstyled or broken within the chat bubbles.
You have two options for integrating these styles into your project. Choose the one that best fits your existing workflow.
Option A: The CSS Global Import
Add the @import rule to the top of your main Tailwind or CSS entry point. This ensures the styles are bundled with your global CSS and are available across all routes.
1/* Ensure this path matches your local project structure after running 'npx telygent-ui add' */
2@import "@/components/ai/components/ai-mdx.css";
3
4@tailwind base;
5@tailwind components;
6@tailwind utilities;Option B: The CSS Global Import
If you prefer to keep your CSS file clean, you can import the stylesheet directly into your top-level Layout or Page file.
1import "@/components/ai/components/ai-mdx.css";
2import "./globals.css";
3
4export default function RootLayout({ children }) {
5 return (
6 <html lang="en">
7 <body>{children}</body>
8 </html>
9 );
10}