xiaohongshu
xiaohongshu
chatkit-frontend
Build production-ready chat UI with OpenAI ChatKit React components. Handles ChatKit installation, useChatKit hook configuration, theming, streaming display, conversation sidebar, and rich widgets. Use when implementing chat interface, migrating from custom UI to ChatKit, or adding AI chat featur...
Full skill instructions
Production-ready skill for implementing OpenAI ChatKit in Next.js applications.
Official Documentation (ALWAYS verify before implementation):
OpenAI ChatKit is a batteries-included framework for building AI-powered chat experiences with:
┌─────────────────────────────────────────────────────────────────────────┐
│ Next.js Frontend │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────────────────────────────┐ │
│ │ ConversationSidebar │ │ ChatKit Component │ │
│ │ (Custom) │ │ ┌────────────────────────────────────┐ │ │
│ │ │ │ │ <ChatKit control={control} /> │ │ │
│ │ - Thread list │◄──►│ │ - Messages │ │ │
│ │ - New chat │ │ │ - Input │ │ │
│ │ - Delete/rename │ │ │ - Streaming │ │ │
│ └──────────────────┘ │ │ - Tool indicators │ │ │
│ │ └────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────▼───────────────────┐ │
│ │ useChatKit Hook │ │
│ │ - api: { url, domainKey } │ │
│ │ - theme: { colorScheme, radius } │ │
│ │ - startScreen: { greeting, prompts } │ │
│ │ - onClientTool: (invocation) => {} │ │
│ └───────────────────┬───────────────────┘ │
└──────────────────────────────────────────────┼───────────────────────────┘
│ SSE Stream
┌────────────────────▼────────────────────┐
│ FastAPI Backend │
│ POST /chatkit │
│ - ChatKit-compatible SSE format │
└─────────────────────────────────────────┘
cd frontend
npm install @openai/chatkit-react
# Check package.json
grep chatkit package.json
// app/chat/page.tsx
'use client';
import { ChatKit, useChatKit } from '@openai/chatkit-react';
export default function ChatPage() {
const { control } = useChatKit({
api: {
url: `${process.env.NEXT_PUBLIC_API_URL}/chatkit`,
domainKey: process.env.NEXT_PUBLIC_OPENAI_DOMAIN_KEY || 'local-dev',
},
});
return (
<div className="h-screen w-full">
<ChatKit control={control} className="h-full w-full" />
</div>
);
}
// app/chat/page.tsx
'use client';
import { ChatKit, useChatKit } from '@openai/chatkit-react';
import { useAuthStore } from '@/stores/auth-store';
import { useConversationStore } from '@/stores/conversation-store';
export default function ChatPage() {
const { user } = useAuthStore();
const { currentConversation, refreshConversations } = useConversationStore();
const { control } = useChatKit({
// API Configuration
api: {
url: `${process.env.NEXT_PUBLIC_API_URL}/chatkit`,
domainKey: process.env.NEXT_PUBLIC_OPENAI_DOMAIN_KEY || 'local-dev',
},
// Theme Configuration
theme: {
colorScheme: 'light', // 'light' | 'dark' | 'system'
radius: 'round', // 'sharp' | 'round' | 'pill'
color: {
accent: { primary: '#0066cc', level: 2 },
grayscale: { hue: 220, tint: 6, shade: -4 },
},
},
// Start Screen
startScreen: {
greeting: `Hello${user?.name ? `, ${user.name}` : ''}! How can I help you today?`,
prompts: [
'Show my tasks',
'Add a new task',
'What tasks are due today?',
'Mark my grocery task as complete',
],
},
// Header Configuration
header: {
enabled: true,
title: 'Task Assistant',
},
// Composer Configuration
composer: {
placeholder: 'Ask about your tasks...',
},
// History (built-in - optional, we use custom sidebar)
history: {
enabled: false, // Disable built-in, use custom ConversationSidebar
},
// Client-side Tool Handling
onClientTool: async (invocation) => {
console.log('Client tool invoked:', invocation.name, invocation.params);
// Handle client-side tools (theme switching, etc.)
if (invocation.name === 'switch_theme') {
// Handle theme change
return { success: true };
}
return { success: false };
},
// Error Handling
onError: ({ error }) => {
console.error('ChatKit error:', error);
},
// Message Events
onMessage: (message) => {
console.log('New message:', message);
// Refresh conversations after message
refreshConversations();
},
});
return (
<div className="h-screen w-full">
<ChatKit
control={control}
className="h-full w-full max-w-4xl mx-auto"
/>
</div>
);
}
frontend/
├── app/
│ └── chat/
│ ├── layout.tsx # Chat layout with sidebar
│ └── page.tsx # ChatKit page
│
├── components/
│ ├── chat/
│ │ └── ChatKitWrapper.tsx # Optional ChatKit wrapper
│ │
│ └── conversation/ # Custom sidebar (keep existing)
│ ├── ConversationSidebar.tsx
│ ├── ConversationList.tsx
│ ├── ConversationItem.tsx
│ └── NewChatButton.tsx
│
├── stores/
│ └── conversation-store.ts # Conversation state (keep existing)
│
└── lib/
└── chatkit/
└── config.ts # ChatKit configuration utilities
'use client';
import { ChatKit, useChatKit } from '@openai/chatkit-react';
import { useTheme } from 'next-themes';
export function ThemedChatKit() {
const { theme } = useTheme();
const isDark = theme === 'dark';
const { control } = useChatKit({
api: { url: '/chatkit', domainKey: 'local-dev' },
theme: {
colorScheme: isDark ? 'dark' : 'light',
radius: 'round',
color: {
grayscale: {
hue: 220,
tint: 6,
shade: isDark ? -1 : -4,
},
accent: {
primary: isDark ? '#f1f5f9' : '#0f172a',
level: 1,
},
},
},
});
return <ChatKit control={control} className="h-full w-full" />;
}
<ChatKit
control={control}
className="
h-full w-full
[--chatkit-bg:hsl(var(--background))]
[--chatkit-text:hsl(var(--foreground))]
[--chatkit-primary:hsl(var(--primary))]
[--chatkit-border:hsl(var(--border))]
"
/>
// app/chat/layout.tsx
'use client';
import { ConversationSidebar } from '@/components/conversation/ConversationSidebar';
export default function ChatLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex h-screen">
{/* Custom Conversation Sidebar */}
<ConversationSidebar />
{/* ChatKit Area */}
<div className="flex-1 overflow-hidden">
{children}
</div>
</div>
);
}
// When user selects a conversation from sidebar
const handleSelectConversation = (conversationId: number) => {
// Update URL or state
router.push(`/chat?thread=${conversationId}`);
// ChatKit will load the thread automatically if configured
};
# Frontend (.env.local)
NEXT_PUBLIC_API_URL=http://localhost:8000
# ChatKit Domain Key (REQUIRED for production)
# Get from: https://platform.openai.com/settings/organization/security/domain-allowlist
NEXT_PUBLIC_OPENAI_DOMAIN_KEY=your-domain-key-here
https://your-app.vercel.app)NEXT_PUBLIC_OPENAI_DOMAIN_KEYNote: localhost works without domain allowlist configuration.
// OLD: Custom chat interface
import { ChatContainer } from '@/components/chat/ChatContainer';
import { MessageList } from '@/components/chat/MessageList';
import { MessageInput } from '@/components/chat/MessageInput';
export default function ChatPage() {
return (
<ChatContainer>
<MessageList messages={messages} />
<MessageInput onSend={sendMessage} />
</ChatContainer>
);
}
// NEW: ChatKit
import { ChatKit, useChatKit } from '@openai/chatkit-react';
export default function ChatPage() {
const { control } = useChatKit({
api: { url: '/chatkit', domainKey: 'local-dev' },
});
return <ChatKit control={control} className="h-full w-full" />;
}
ConversationSidebar - Better UX than built-in historyconversation-store.ts - Thread management stateChatContainer.tsx - Replaced by ChatKitMessageList.tsx - Replaced by ChatKitMessageInput.tsx - Replaced by ChatKitStreamingMessage.tsx - Replaced by ChatKit@openai/chatkit-react installed/chatuseChatKit hook configured with API URL/chatkit endpoint working// Ensure client-side rendering
'use client';
// Check control is initialized
if (!control) return <div>Loading...</div>;
# Backend: Add ChatKit origins to CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "https://your-app.vercel.app"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Backend: Use correct SSE format for ChatKit
yield f"data: {json.dumps({'type': 'text', 'content': chunk})}\n\n"
yield "data: [DONE]\n\n"
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience