Skip to main content

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