Documentation Index
Fetch the complete documentation index at: https://runcrate.ai/docs/llms.txt
Use this file to discover all available pages before exploring further.
Build a streaming chatbot with Next.js App Router, @runcrate/ai, and the Vercel AI SDK’s useChat hook. Under 50 lines of code for a working chat interface.
Prerequisites
npx create-next-app@latest my-chatbot --app --typescript --tailwind
cd my-chatbot
npm install @runcrate/ai ai
Set your API key in .env.local:
RUNCRATE_API_KEY=rc_live_YOUR_API_KEY
API route
// app/api/chat/route.ts
import { runcrate } from '@runcrate/ai';
import { streamText } from 'ai';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: runcrate('deepseek-ai/DeepSeek-V3'),
system: 'You are a helpful assistant. Be concise and direct.',
messages,
});
return result.toDataStreamResponse();
}
Chat component
// app/page.tsx
'use client';
import { useChat } from '@ai-sdk/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
return (
<div className="mx-auto flex h-screen max-w-2xl flex-col p-4">
<h1 className="mb-4 text-xl font-medium">AI Chat</h1>
<div className="flex-1 space-y-4 overflow-y-auto pb-4">
{messages.map((m) => (
<div key={m.id} className={m.role === 'user' ? 'text-right' : 'text-left'}>
<span className="inline-block rounded-lg bg-gray-100 px-3 py-2 dark:bg-gray-800">
{m.content}
</span>
</div>
))}
</div>
<form onSubmit={handleSubmit} className="flex gap-2">
<input
value={input}
onChange={handleInputChange}
placeholder="Ask anything..."
className="flex-1 rounded-lg border px-3 py-2"
/>
<button type="submit" disabled={isLoading}
className="rounded-lg bg-blue-600 px-4 py-2 text-white disabled:opacity-50">
Send
</button>
</form>
</div>
);
}
Run npm run dev and open http://localhost:3000.
Add a system prompt selector
// app/api/chat/route.ts
import { runcrate } from '@runcrate/ai';
import { streamText } from 'ai';
const PERSONAS: Record<string, string> = {
default: 'You are a helpful assistant.',
coding: 'You are a senior software engineer. Give practical code examples.',
writing: 'You are a writing coach. Help improve clarity and style.',
};
export async function POST(req: Request) {
const { messages, data } = await req.json();
const result = streamText({
model: runcrate('deepseek-ai/DeepSeek-V3'),
system: PERSONAS[data?.persona] || PERSONAS.default,
messages,
});
return result.toDataStreamResponse();
}
Tips
- DeepSeek-V3 is the recommended default — fast, cheap, strong across general tasks.
useChat manages conversation history client-side. Each POST sends the full message array.
- Error handling:
useChat exposes an error property you can render in the UI.
Next steps