| name | ai-sdk-5 |
| description | Vercel AI SDK 5 patterns. Trigger: When building AI features with AI SDK v5 (chat, streaming, tools/function calling, UIMessage parts), including migration from v4.
|
| license | Apache-2.0 |
| metadata | {"author":"prowler-cloud","version":"1.0","scope":["root","ui"],"auto_invoke":"Building AI chat features"} |
| allowed-tools | Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task |
Breaking Changes from AI SDK 4
import { useChat } from "ai";
const { messages, handleSubmit, input, handleInputChange } = useChat({
api: "/api/chat",
});
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
const { messages, sendMessage } = useChat({
transport: new DefaultChatTransport({ api: "/api/chat" }),
});
Client Setup
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
import { useState } from "react";
export function Chat() {
const [input, setInput] = useState("");
const { messages, sendMessage, isLoading, error } = useChat({
transport: new DefaultChatTransport({ api: "/api/chat" }),
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim()) return;
sendMessage({ text: input });
setInput("");
};
return (
<div>
<div>
{messages.map((message) => (
<Message key={message.id} message={message} />
))}
</div>
< =>
setInput(e.target.value)}
placeholder="Type a message..."
disabled={isLoading}
/>
Send
{error && Error: {error.message}}
);
}
UIMessage Structure (v5)
interface UIMessage {
id: string;
role: "user" | "assistant" | "system";
parts: MessagePart[];
}
type MessagePart =
| { type: "text"; text: string }
| { type: "image"; image: string }
| { type: "tool-call"; toolCallId: string; toolName: string; args: unknown }
| { type: "tool-result"; toolCallId: string; result: unknown };
function getMessageText(message: UIMessage): string {
return message.parts
.filter((part): part is { type: "text"; text: string } => part.type === "text")
.map( part.)
.();
}
() {
(
);
}
Server-Side (Route Handler)
import { openai } from "@ai-sdk/openai";
import { streamText } from "ai";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = await streamText({
model: openai("gpt-4o"),
messages,
system: "You are a helpful assistant.",
});
return result.toDataStreamResponse();
}
With LangChain
import { toUIMessageStream } from "@ai-sdk/langchain";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, AIMessage } from "@langchain/core/messages";
export async function POST(req: Request) {
const { messages } = await req.json();
const model = new ChatOpenAI({
modelName: "gpt-4o",
streaming: true,
});
const langchainMessages = messages.map((m) => {
const text = m.parts
.filter((p) => p.type === "text")
.map((p) => p.text)
.join("");
return m.role === "user"
? new (text)
: (text);
});
stream = model.(langchainMessages);
(stream).();
}
Streaming with Tools
import { openai } from "@ai-sdk/openai";
import { streamText, tool } from "ai";
import { z } from "zod";
const result = await streamText({
model: openai("gpt-4o"),
messages,
tools: {
getWeather: tool({
description: "Get weather for a location",
parameters: z.object({
location: z.string().describe("City name"),
}),
execute: async ({ location }) => {
return { temperature: 72, condition: "sunny" };
},
}),
},
});
useCompletion (Text Generation)
import { useCompletion } from "@ai-sdk/react";
import { DefaultCompletionTransport } from "ai";
const { completion, complete, isLoading } = useCompletion({
transport: new DefaultCompletionTransport({ api: "/api/complete" }),
});
await complete("Write a haiku about");
Error Handling
const { error, messages, sendMessage } = useChat({
transport: new DefaultChatTransport({ api: "/api/chat" }),
onError: (error) => {
console.error("Chat error:", error);
toast.error("Failed to send message");
},
});
{error && (
<div className="error">
{error.message}
<button onClick={() => sendMessage({ text: lastInput })}>
Retry
</button>
</div>
)}