Official package · Realtime building blocks
Resumable AI chat streams for the Vercel AI SDK
A transport for useChat(): answers stream over a channel, so they survive dropped connections, resume after a reload and reach every tab and device. Works with AI SDK 5, 6 and 7.
@hibira-io/ai-sdknpm ↗GitHub ↗
- Works with any useChat: React, Vue, Svelte and Angular.
- The API route answers at once, and the answer runs to the end in the background, with no Redis or stream store to run.
- Merges text deltas into events under 3,500 bytes, and catches up from channel history with resume: true (Hobby plans and up).
Sign in to see these snippets with your own cluster host. Sign in
Install
npm install @hibira-io/ai-sdk pusher-js pusherSet it up
'use client'; import { useChat } from '@ai-sdk/react'; import Pusher from 'pusher-js'; import { HibiraChatTransport } from '@hibira-io/ai-sdk'; const pusher = new Pusher(process.env.NEXT_PUBLIC_HIBIRA_KEY!, { cluster: 'hkg', wsHost: 'ws.hibira.io', channelAuthorization: { endpoint: '/api/hibira/auth', transport: 'ajax' }, }); const transport = new HibiraChatTransport({ pusher, api: '/api/chat' }); export function Chat({ id, initialMessages }) { const { messages, sendMessage } = useChat({ id, messages: initialMessages, transport, resume: true }); // render messages as usual }Use it
// app/api/chat/route.ts import { after } from 'next/server'; import { streamText, convertToModelMessages } from 'ai'; import Pusher from 'pusher'; import { publishUIMessageStream } from '@hibira-io/ai-sdk/server'; const pusher = new Pusher({ appId: process.env.HIBIRA_APP_ID!, key: process.env.NEXT_PUBLIC_HIBIRA_KEY!, secret: process.env.HIBIRA_SECRET!, host: 'ws.hibira.io', useTLS: true, }); export async function POST(req: Request) { const { id, messages, runId } = await req.json(); const result = streamText({ model, messages: await convertToModelMessages(messages) }); after(() => publishUIMessageStream(pusher, { chatId: id, runId, stream: result.toUIMessageStream({ originalMessages: messages, onFinish: ({ messages }) => saveChat(id, messages) }), }), ); return Response.json({ runId }, { status: 202 }); }
Before you start
- The app secret is shown only once, when you create the app or rotate its secret. Keep it on your server, never in a browser or game build.
- The transport subscribes to private-ai-chat-{chatId}. Your auth endpoint should allow that channel only for the chat’s owner.
- Turn on channel history in the app’s settings (Hobby plans and up), so a reloaded page can resume an answer that is still being written.
Use the app key from your dashboard; the secret stays on your server. Channels, events and authorization endpoints work exactly as they do with Pusher. Create your free account →