Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    brunoalan

    ai-sdk-5

    brunoalan/ai-sdk-5
    AI & ML

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    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.

    SKILL.md

    Breaking Changes from AI SDK 4

    // ❌ 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

    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}>
            <input
              value={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)

    // ❌ Old: message.content was a string
    // ✅ New: message.parts is an array
    
    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 };
    
    // Extract text from parts
    function getMessageText(message: UIMessage): string {
      return message.parts
        .filter((part): part is { type: "text"; text: string } => part.type === "text")
        .map((part) => part.text)
        .join("");
    }
    
    // Render message
    function 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)

    // app/api/chat/route.ts
    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

    // app/api/chat/route.ts
    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,
      });
    
      // Convert UI messages to LangChain format
      const 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

    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 data
            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" }),
    });
    
    // Trigger completion
    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");
      },
    });
    
    // Display error
    {error && (
      <div className="error">
        {error.message}
        <button onClick={() => sendMessage({ text: lastInput })}>
          Retry
        </button>
      </div>
    )}
    
    Recommended Servers
    Vercel Grep
    Vercel Grep
    Cloudflare AI Search
    Cloudflare AI Search
    Jina AI
    Jina AI
    Repository
    brunoalan/agents-skills
    Files