Next.js App Router
Build a chat application with Next.js App Router, Halo, and the Vercel AI SDK's useChat hook.
Setup
bash
pnpm add @halo-ai/core @halo-ai/adapters @halo-ai/stream @ai-sdk/reactAPI Route
Create app/api/chat/route.ts:
ts
import { Halo, tool } from "@halo-ai/core";
import { DeepSeekAdapter } from "@halo-ai/adapters";
import { toDataStream } from "@halo-ai/stream";
const halo = new Halo({
adapter: new DeepSeekAdapter({
apiKey: process.env.DEEPSEEK_API_KEY!,
}),
});
export async function POST(req: Request) {
const { messages } = await req.json();
const agent = halo.agent({
system: "You are a helpful assistant.",
// Optional: tools with auto-execute
tools: {
get_weather: tool({
description: "Get current weather for a city",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
execute: async ({ city }: { city: string }) => {
const data: Record<string, string> = {
beijing: "5°C, clear",
paris: "12°C, cloudy",
};
return data[city.toLowerCase()] ?? `${city}: 20°C, sunny`;
},
}),
},
});
return toDataStream(agent.sdkStream(messages));
}Chat Component
Create components/chat.tsx:
tsx
"use client";
import { useChat } from "@ai-sdk/react";
export function Chat() {
const { messages, input, handleInputChange, handleSubmit, status } = useChat();
return (
<div>
<div>
{messages.map((m) => (
<div key={m.id} className={m.role === "user" ? "user" : "assistant"}>
{m.content}
</div>
))}
</div>
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} placeholder="Type a message..." />
<button type="submit" disabled={status !== "ready"}>Send</button>
</form>
</div>
);
}How It Works
useChatsends all messages to/api/chaton each submitagent.sdkStream(messages)converts UIMessages, hydrates prior history, and streams the responsetoDataStream()wraps the stream in Vercel AI SDK's SSE protocol (0:/d:)useChatautomatically parses the SSE stream and updates the UI
Cache First
The system prompt and tool definitions are part of the stable prefix. DeepSeek caches them automatically. Only the conversation turns change between requests �?your prefix tokens are billed at ~74% discount.
Full Example
See the Next.js example for a complete chat app with Tailwind styling and tool-call visualization.