Node.js/TypeScript SDK for building ChatKit custom backend integrations with OpenAI Agents SDK.
- 🤖 OpenAI Agents SDK Integration - Seamless integration with the OpenAI Agents SDK for AI-powered conversations
- 🔄 Streaming Support - Real-time Server-Sent Events (SSE) for streaming responses
- 🎨 Rich Widgets - Display charts, cards, forms, and interactive UI components
- 🛠️ Client-Side Tools - Execute tools on the client side with automatic synchronization
- 📦 Type-Safe - Full TypeScript support with comprehensive type definitions
- 🔌 Framework Agnostic - Works with Express, Fastify, or any Node.js HTTP framework
npm install chatkit-node-backend-sdk @openai/agents zodCreate a custom store implementation to persist threads and messages:
import { Store, ThreadMetadata, ThreadItem } from 'chatkit-node-backend-sdk';
class MyStore extends Store {
async loadThread(threadId: string, context: any) {
// Load thread from your database
return await db.threads.findById(threadId);
}
async saveThread(thread: ThreadMetadata, context: any) {
await db.threads.save(thread);
}
async loadThreadItems(threadId: string, after: string | null, limit: number, order: string, context: any) {
const items = await db.items.findByThread(threadId, { after, limit, order });
return {
data: items,
has_more: items.length === limit,
after: items[items.length - 1]?.id || null
};
}
async addThreadItem(threadId: string, item: ThreadItem, context: any) {
await db.items.create({ threadId, ...item });
}
// Implement other required Store methods...
}Extend ChatKitServer and implement the respond method:
import { ChatKitServer, agents } from 'chatkit-node-backend-sdk';
import { Agent, run } from '@openai/agents';
class MyChatKitServer extends ChatKitServer {
constructor(store: Store) {
super(store);
this.agent = new Agent({
model: 'gpt-5',
name: 'Assistant',
instructions: 'You are a helpful AI assistant.',
tools: [/* your tools */]
});
}
async *respond(thread, inputUserMessage, context) {
if (!inputUserMessage) return;
// Create AgentContext with widget support
const agentContext = agents.createAgentContext(thread, this.store, context);
// Convert ChatKit message to Agent SDK format
const agentInput = await agents.simpleToAgentInput(inputUserMessage);
// Run the agent with streaming
const runnerStream = await run(this.agent, agentInput, {
stream: true,
context: agentContext
});
// Stream events to the client
for await (const event of agents.streamAgentResponse(agentContext, runnerStream)) {
yield event;
}
// Auto-generate thread title
if (!thread.title) {
thread.title = this.generateTitle(inputUserMessage);
}
}
generateTitle(message) {
const text = message.content
.filter(c => c.type === 'input_text')
.map(c => c.text)
.join(' ');
return text.slice(0, 50) + (text.length > 50 ? '...' : '');
}
}Use with Express (or any framework):
import express from 'express';
const app = express();
app.use(express.json());
const store = new MyStore();
const server = new MyChatKitServer(store);
app.post('/chatkit', async (req, res) => {
const context = { userId: req.headers['x-user-id'] || 'anonymous' };
const result = await server.process(JSON.stringify(req.body), context);
if (result.isStreaming) {
// Set SSE headers
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// Stream events
for await (const chunk of result) {
res.write(chunk);
}
res.end();
} else {
res.json(result.toJSON());
}
});
app.listen(3000, () => {
console.log('ChatKit server running on http://localhost:3000');
});Display rich UI components in your chat:
import { tool } from '@openai/agents';
import { z } from 'zod';
const showChartTool = tool({
name: 'show_chart',
description: 'Display a chart to the user',
parameters: z.object({
title: z.string()
}),
execute: async ({ title }, { context }) => {
await context.streamWidget({
type: 'Card',
children: [
{ type: 'Title', value: title },
{
type: 'Chart',
data: [
{ month: 'Jan', sales: 30 },
{ month: 'Feb', sales: 45 },
{ month: 'Mar', sales: 60 }
],
series: [
{ type: 'bar', dataKey: 'sales', label: 'Sales', color: 'blue' }
],
xAxis: 'month',
showLegend: true
}
]
});
return 'Chart displayed';
}
});Execute tools on the client side:
const addToTodoTool = tool({
name: 'add_to_todo_list',
description: 'Add a task to the user\'s todo list',
parameters: z.object({
task: z.string(),
priority: z.enum(['low', 'medium', 'high'])
}),
execute: async ({ task, priority }, { context }) => {
// Trigger client-side execution
context.clientToolCall = {
name: 'add_to_todo_list',
arguments: { task, priority }
};
return `I'll add "${task}" to your todo list`;
}
});- Full Documentation - Complete guides and API reference
- Server Integration Guide - Detailed server setup
- Widgets Guide - Widget components and examples
- Actions Guide - Client-side interactions
See the examples/ directory for complete working examples:
- Basic Server - Simple ChatKit server setup
- Advanced Server - Full-featured server with widgets, tools, and reasoning
- Custom Store - Database-backed store implementation
- Node.js >= 18.0.0
- OpenAI API key (for Agents SDK)
Full TypeScript API documentation is available at: https://evotechmike.github.io/chatkit-node-backend-sdk/api/
Contributions are welcome! Please feel free to submit a Pull Request.
MIT © EvoTechMike