| name | openai-chatkit-skill |
| description | Integrate OpenAI ChatKit for conversational AI interface |
| when-to-use | Building chat UI, handling messages, tool calls display |
OpenAI ChatKit Skill
Instructions
This skill provides guidance for integrating OpenAI's ChatKit interface for conversational AI experiences.
Project Structure
src/
├── components/
│ └── chat/
│ ├── ChatWindow.tsx # Main chat container
│ ├── ChatMessage.tsx # Individual message display
│ ├── ChatInput.tsx # User input area
│ ├── ChatToolbar.tsx # Quick actions toolbar
│ └── typing-indicator.tsx
├── hooks/
│ └── useChat.ts # Chat state management
├── lib/
│ └── openai.ts # OpenAI client configuration
└── types/
└── chat.ts # Chat type definitions
Type Definitions
export interface ChatMessage {
id: string
role: 'user' | 'assistant' | 'system'
content: string
timestamp: Date
tools?: ToolCall[]
}
export interface ToolCall {
id: string
name: string
arguments: Record<string, unknown>
result?: unknown
}
export interface ChatState {
messages: ChatMessage[]
isLoading: boolean
error: string | null
}
export interface UseChatReturn extends ChatState {
sendMessage: (content: string) => Promise<void>
clearMessages: () => void
retry: () => Promise<void>
}
OpenAI Client Setup
import OpenAI from 'openai'
export const openai = new OpenAI({
apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY || process.env.OPENAI_API_KEY,
})
export interface ChatCompletionOptions {
model?: string
temperature?: number
max_tokens?: number
stream?: boolean
}
export async function createChatCompletion(
messages: ChatMessage[],
options: ChatCompletionOptions = {}
) {
const response = await openai.chat.completions.create({
model: options.model || 'gpt-4o',
messages: messages.map(m => ({
role: m.role,
content: m.content,
})),
temperature: options.temperature ?? 0.7,
: options. ?? ,
: options. ?? ,
: (),
})
response
}
() {
[
{
: ,
: {
: ,
: ,
: {
: ,
: {},
},
},
},
{
: ,
: {
: ,
: ,
: {
: ,
: {
: { : , : },
: { : , : },
: { : , : },
},
: [],
},
},
},
{
: ,
: {
: ,
: ,
: {
: ,
: {
: { : , : },
: { : , : },
: { : , : },
},
: [],
},
},
},
{
: ,
: {
: ,
: ,
: {
: ,
: {
: { : , : },
},
: [],
},
},
},
]
}
Chat Hook
'use client'
import { useCallback, useState } from 'react'
import { ChatMessage, UseChatReturn } from '@/types/chat'
import { createChatCompletion } from '@/lib/openai'
import { v4 as uuidv4 } from 'uuid'
const SYSTEM_PROMPT = `You are a helpful AI assistant for task management.
You can help users create, update, and manage their tasks through natural language.
Always be helpful, friendly, and concise in your responses.`
export function useChat(): UseChatReturn {
const [messages, setMessages] = useState<ChatMessage[]>([
{
id: 'system',
role: 'system',
content: SYSTEM_PROMPT,
timestamp: new Date(),
},
])
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const sendMessage = useCallback(async (content: string) => {
: = {
: (),
: ,
content,
: (),
}
( [...prev, userMessage])
()
()
{
response = (
[...messages, userMessage],
{ : }
)
: = {
: (),
: ,
: response.[]?.?. || ,
: (),
}
( [...prev, assistantMessage])
} (err) {
(err ? err. : )
} {
()
}
}, [messages])
clearMessages = ( {
([
{
: ,
: ,
: ,
: (),
},
])
}, [])
retry = ( () => {
lastUserMessage = [...messages].().( m. === )
(lastUserMessage) {
(lastUserMessage.)
}
}, [messages, sendMessage])
{
messages,
isLoading,
error,
sendMessage,
clearMessages,
retry,
}
}
Chat Window Component
'use client'
import { useRef, useEffect } from 'react'
import { useChat } from '@/hooks/useChat'
import { ChatMessage } from './ChatMessage'
import { ChatInput } from './ChatInput'
export function ChatWindow() {
const { messages, isLoading, error, sendMessage } = useChat()
const messagesEndRef = useRef<HTMLDivElement>(null)
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
}, [messages])
const handleSend = async (content: string) => {
await sendMessage(content)
}
const assistantMessages = messages.filter(m => m.role === 'assistant')
const userMessages = messages.filter(m => m.role === 'user')
(
)
}
Chat Message Component
import { ChatMessage as ChatMessageType } from '@/types/chat'
interface ChatMessageProps {
message: ChatMessageType
isLatest?: boolean
}
export function ChatMessage({ message, isLatest }: ChatMessageProps) {
const isUser = message.role === 'user'
return (
<div className={`flex ${isUser ? 'justify-end' : 'justify-start'}`}>
<div className={`max-w-[80%] ${isUser ? 'order-2' : 'order-1'}`}>
{/* Avatar */}
<div className={`flex items-center gap-2 mb-1 ${isUser ? 'flex-row-reverse' : ''}`}>
<div className={`
${ ? '' ' '}
`}>
{isUser ? 'U' : 'AI'}
{new Date(message.timestamp).toLocaleTimeString()}
{/* Message bubble */}
{message.content}
{/* Tool calls indicator */}
{message.tools && message.tools.length > 0 && (
{message.tools.map(tool => (
{tool.name}
))}
)}
)
}
Chat Input Component
'use client'
import { useState, useRef, useEffect } from 'react'
interface ChatInputProps {
onSend: (content: string) => Promise<void>
isLoading: boolean
}
export function ChatInput({ onSend, isLoading }: ChatInputProps) {
const [input, setInput] = useState('')
const textareaRef = useRef<HTMLTextAreaElement>(null)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!input.trim() || isLoading) return
const content = input.trim()
setInput('')
await onSend(content)
}
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === && !e.) {
e.()
(e)
}
}
( {
(textareaRef.) {
textareaRef... =
textareaRef... =
}
}, [input])
(
)
}
Streaming Response Example
export async function* streamChat(messages: ChatMessage[]) {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: messages.map(m => ({ role: m.role, content: m.content })),
stream: true,
})
for await (const chunk of response) {
const content = chunk.choices[0]?.delta?.content
if (content) {
yield content
}
}
}
async function handleStreamingSend(content: string) {
const encoder = new TextEncoder()
const stream = await streamChat([...messages, userMessage])
for await ( chunk stream) {
( prev + chunk)
}
}