<< All versions
Skill v1.0.1
currentAutomated scan100/100gentleman-programming/gentleman-skills/ai-sdk-5
1 files
──Details
PublishedSeptember 30, 2026 at 08:24 AM
Content Hashsha256:9bf57821c2f08cec...
Git SHAc8036a378936
Bump Typepatch
──Files
Files (1 file, 5.4 KB)
SKILL.md5.4 KBactive
SKILL.md · 238 lines · 5.4 KB
version: "1.0.1" name: ai-sdk-5 description: > Vercel AI SDK 5 patterns. Trigger: When building AI chat features - breaking changes from v4. license: Apache-2.0 metadata: author: gentleman-programming version: "1.0"
Breaking Changes from AI SDK 4
typescript
// ❌ AI SDK 4 (OLD)import { useChat } from "ai";const { messages, handleSubmit, input, handleInputChange } = useChat({api: "/api/chat",});// ✅ AI SDK 5 (NEW)import { useChat } from "@ai-sdk/react";import { DefaultChatTransport } from "ai";const { messages, sendMessage } = useChat({transport: new DefaultChatTransport({ api: "/api/chat" }),});
Client Setup
typescript
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><form onSubmit={handleSubmit}><inputvalue={input}onChange={(e) => setInput(e.target.value)}placeholder="Type a message..."disabled={isLoading}/><button type="submit" disabled={isLoading}>Send</button></form>{error && <div>Error: {error.message}</div>}</div>);}
UIMessage Structure (v5)
typescript
// ❌ Old: message.content was a string// ✅ New: message.parts is an arrayinterface 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 };// Extract text from partsfunction getMessageText(message: UIMessage): string {return message.parts.filter((part): part is { type: "text"; text: string } => part.type === "text").map((part) => part.text).join("");}// Render messagefunction Message({ message }: { message: UIMessage }) {return (<div className={message.role === "user" ? "user" : "assistant"}>{message.parts.map((part, index) => {if (part.type === "text") {return <p key={index}>{part.text}</p>;}if (part.type === "image") {return <img key={index} src={part.image} alt="" />;}return null;})}</div>);}
Server-Side (Route Handler)
typescript
// app/api/chat/route.tsimport { 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
typescript
// app/api/chat/route.tsimport { 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,});// Convert UI messages to LangChain formatconst langchainMessages = messages.map((m) => {const text = m.parts.filter((p) => p.type === "text").map((p) => p.text).join("");return m.role === "user"? new HumanMessage(text): new AIMessage(text);});const stream = await model.stream(langchainMessages);return toUIMessageStream(stream).toDataStreamResponse();}
Streaming with Tools
typescript
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 }) => {// Fetch weather datareturn { temperature: 72, condition: "sunny" };},}),},});
useCompletion (Text Generation)
typescript
import { useCompletion } from "@ai-sdk/react";import { DefaultCompletionTransport } from "ai";const { completion, complete, isLoading } = useCompletion({transport: new DefaultCompletionTransport({ api: "/api/complete" }),});// Trigger completionawait complete("Write a haiku about");
Error Handling
typescript
const { error, messages, sendMessage } = useChat({transport: new DefaultChatTransport({ api: "/api/chat" }),onError: (error) => {console.error("Chat error:", error);toast.error("Failed to send message");},});// Display error{error && (<div className="error">{error.message}<button onClick={() => sendMessage({ text: lastInput })}>Retry</button></div>)}
Keywords
ai sdk, vercel ai, chat, streaming, langchain, openai, llm