Blocks Overview

PreviousNext

Learn about AI SDK integration and how blocks provide complete AI applications and patterns.

AI SDK Agents provides complete AI applications and patterns built on top of the Vercel AI SDK, shadcn/ui, and AI Elements.

What are Blocks?

Blocks are complete, production-ready AI applications that you can copy and customize:

  • Full-stack AI agents with tool calling and multi-step workflows
  • AI tools and utilities for common tasks
  • AI patterns for research, analysis, and content generation
  • AI artifacts like dynamic tables, charts, and forms
  • Marketing AI components for landing pages and user acquisition
  • Problem-solving components for common AI challenges
  • Web scraping and data processing tools for content extraction
  • Human-in-the-loop workflows for safe AI interactions

Block Categories

AI Agent Patterns

Sophisticated agent implementations with advanced workflows:

AI Artifact Blocks

Interactive AI-generated content and data visualization:

AI Elements Blocks

Basic AI interaction patterns using AI Elements:

AI SDK Integration Blocks

Specific AI SDK features and provider integrations:

Web Search & Scraping Tools

Powerful tools for web content extraction and search:

Marketing & UI Components

Components for marketing and user interface:

AI Gateway & Rate Limiting

Vercel AI Gateway

Many blocks integrate with Vercel's AI Gateway for enhanced performance and reliability:

  • Unified API: Single endpoint for multiple AI providers
  • Automatic retries: Built-in retry logic for failed requests
  • Request deduplication: Prevents duplicate requests
  • Analytics: Detailed usage analytics and monitoring
  • Cost optimization: Automatic provider selection based on cost

Upstash Rate Limiting

All production blocks include rate limiting using Upstash Redis:

import { Ratelimit } from "@upstash/ratelimit"
import { Redis } from "@upstash/redis"
 
// Create a new ratelimiter
const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "10 s"),
  analytics: true,
  prefix: "@upstash/ratelimit",
})
 
export async function checkRateLimit(identifier: string) {
  const { success, limit, reset, remaining } = await ratelimit.limit(identifier)
 
  return {
    success,
    limit,
    reset,
    remaining,
    headers: {
      "X-RateLimit-Limit": limit.toString(),
      "X-RateLimit-Remaining": remaining.toString(),
      "X-RateLimit-Reset": reset.toString(),
    },
  }
}

Rate Limiting Configuration

Different blocks use different rate limiting strategies:

  • AI Agents: 200 requests per day per IP
  • Web Search Tools: 10 requests per minute
  • Artifact Generation: 100 requests per day per IP
  • Human-in-the-Loop: 50 requests per hour per user

Using Blocks

1. Browse Available Blocks

Visit the blocks page to see all available blocks organized by category.

2. Copy Block Code

Click on any block to view its implementation and copy the code directly into your project.

3. Install Dependencies

Most blocks require the AI SDK and provider packages:

pnpm add ai @ai-sdk/react @ai-sdk/openai @ai-sdk/google @upstash/ratelimit @upstash/redis

4. Set Environment Variables

Configure your AI provider API keys and rate limiting:

# .env.local
OPENAI_API_KEY=your_openai_api_key
GOOGLE_API_KEY=your_google_api_key
CLAUDE_API_KEY=your_claude_api_key
 
# Required for rate limiting (recommended for production)
UPSTASH_REDIS_REST_URL=your_redis_url
UPSTASH_REDIS_REST_TOKEN=your_redis_token
 
# Optional: Vercel AI Gateway
VERCEL_AI_GATEWAY_URL=your_gateway_url

5. Customize

Modify the block to fit your specific needs:

export function MyCustomAgent() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: "/api/my-custom-agent",
    initialMessages: [
      {
        id: "1",
        role: "assistant",
        content: "Hello! I'm your custom AI agent. How can I help?",
      },
    ],
  })
 
  return (
    <div className="mx-auto max-w-4xl">
      {/* Your customized implementation */}
    </div>
  )
}

Block Structure

Each block follows a consistent structure for easy integration:

block-name/
├── app/
│   ├── layout.tsx          # Block layout wrapper
│   ├── page.tsx           # Main page component
│   └── api/               # API routes for AI functionality
│       └── route-name/
│           └── route.ts   # API endpoint implementation
├── components/            # React components
│   ├── demo-name.tsx     # Main demo component
│   └── ...               # Additional UI components
├── lib/                   # Utilities and configurations
│   ├── rate-limit.ts     # Rate limiting implementation
│   ├── request-utils.ts  # Request validation utilities
│   └── ...               # AI tools and schemas
├── hooks/                 # Custom React hooks (optional)
├── README.md             # Comprehensive documentation
└── package.json          # Dependencies and metadata

Key Files Explained

  • app/page.tsx: Main page component that renders the demo
  • app/layout.tsx: Layout wrapper for consistent styling
  • app/api/*/route.ts: API endpoints handling AI functionality with rate limiting
  • components/*.tsx: React components following clean architecture patterns
  • lib/rate-limit.ts: Upstash Redis rate limiting implementation
  • lib/request-utils.ts: Request validation and error handling utilities
  • README.md: Detailed documentation with setup instructions and examples

AI Agent Patterns

Sophisticated agent implementations with advanced workflows:

Web Search & Scraping Tools

Powerful tools for web content extraction and search:

AI Artifacts

Interactive AI-generated content and data visualization:

Best Practices

AI SDK Integration

  • Use streaming: Always prefer streaming responses for better UX
  • Handle errors: Implement proper error handling and fallbacks
  • Type safety: Use TypeScript for better development experience
  • Rate limiting: Implement rate limiting for production use
  • Tool validation: Use Zod schemas for input validation
  • Empty states: Always include empty state components when no data is present

Block Development

  • Follow patterns: Use established patterns from existing blocks
  • Document everything: Provide clear documentation and examples
  • Test thoroughly: Ensure blocks work across different scenarios
  • Optimize performance: Consider bundle size and runtime performance
  • Modular architecture: Keep components focused on single responsibilities
  • Custom hooks: Use custom hooks for complex state logic

Security

  • API key protection: Never expose API keys in client-side code
  • Input validation: Validate all user inputs with Zod schemas
  • Rate limiting: Prevent abuse with proper rate limiting
  • Content filtering: Implement content moderation when needed
  • Error boundaries: Use React error boundaries for graceful failures

Production Considerations

  • Environment variables: Use proper environment variable management
  • Monitoring: Implement logging and monitoring for production
  • Caching: Use appropriate caching strategies for API calls
  • Database connections: Manage database connections efficiently
  • Memory management: Avoid memory leaks in long-running processes

Common Patterns

API Route Pattern

// app/api/example/route.ts
import { openai } from "@ai-sdk/openai"
import { generateText } from "ai"
 
import { checkRateLimit } from "@/lib/rate-limit"
 
export async function POST(req: Request) {
  try {
    const { prompt } = await req.json()
 
    // Rate limiting check
    const identifier = req.headers.get("x-forwarded-for") ?? "unknown"
    const { success } = await checkRateLimit(identifier)
 
    if (!success) {
      return new Response("Rate limit exceeded", { status: 429 })
    }
 
    // AI SDK integration
    const result = await generateText({
      model: openai("gpt-4"),
      prompt: prompt,
    })
 
    return Response.json({ result: result.text })
  } catch (error) {
    console.error("API Error:", error)
    return new Response("Internal Server Error", { status: 500 })
  }
}

Component Pattern

// components/example-demo.tsx
"use client"
 
import { useChat } from "ai/react"
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
 
export function ExampleDemo() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: "/api/example",
  })
 
  if (messages.length === 0) {
    return (
      <Empty className="mx-auto mt-6 max-w-2xl">
        <EmptyHeader>
          <EmptyMedia variant="icon">
            <div className="flex size-12 items-center justify-center rounded-full border bg-white p-1 shadow-sm">
              <Icon className="size-6" />
            </div>
          </EmptyMedia>
          <EmptyTitle>Example Demo</EmptyTitle>
          <EmptyDescription>
            Description of the component with{" "}
            <span className="border-border bg-muted rounded-sm border-[1px] px-1 py-0.5 font-mono font-light tracking-tight">
              ComponentName
            </span>{" "}
            highlighted.
          </EmptyDescription>
        </EmptyHeader>
        <EmptyContent>
          <div className="space-y-4">
            <div>
              <p className="text-muted-foreground mb-3 text-sm">
                Usage instructions and helpful context.
              </p>
            </div>
            <div className="space-y-2">
              <p className="text-sm font-medium">Example prompts:</p>
              <ul className="text-muted-foreground space-y-1 text-sm">
                <li>• "Example prompt 1"</li>
                <li>• "Example prompt 2"</li>
              </ul>
            </div>
          </div>
        </EmptyContent>
      </Empty>
    )
  }
 
  return (
    <div className="mx-auto max-w-4xl">
      {/* Chat interface implementation */}
    </div>
  )
}

Tool Definition Pattern

// lib/tools.ts
import { tool } from "ai"
import { z } from "zod"
 
export const exampleTool = tool({
  description: "Tool description for AI understanding",
  inputSchema: z.object({
    parameter: z.string().describe("Parameter description"),
    optional: z.string().optional().describe("Optional parameter"),
  }),
  execute: async ({ parameter, optional }) => {
    // Tool implementation
    return {
      result: "Tool execution result",
      metadata: {
        processedAt: new Date().toISOString(),
        parameter,
      },
    }
  },
})

Examples

Simple Chat Block

import { useChat } from "ai/react"
 
import {
  Conversation,
  ConversationContent,
  Message,
  MessageContent,
  PromptInput,
  PromptInputBody,
  PromptInputSubmit,
  PromptInputTextarea,
} from "@/components/ai-elements"
 
export function SimpleChatBlock() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: "/api/chat",
  })
 
  return (
    <div className="flex h-screen flex-col">
      <Conversation>
        <ConversationContent>
          {messages.map((message) => (
            <Message key={message.id} from={message.role}>
              <MessageContent>{message.content}</MessageContent>
            </Message>
          ))}
        </ConversationContent>
      </Conversation>
 
      <PromptInput onSubmit={handleSubmit}>
        <PromptInputBody>
          <PromptInputTextarea
            value={input}
            onChange={handleInputChange}
            placeholder="Type your message..."
          />
        </PromptInputBody>
        <PromptInputSubmit />
      </PromptInput>
    </div>
  )
}

Tool Calling Block

import { useChat } from "ai/react"
import { z } from "zod"
 
const tools = {
  getWeather: {
    description: "Get the current weather for a location",
    parameters: z.object({
      location: z.string().describe("The city and state"),
    }),
    execute: async ({ location }) => {
      // Simulate weather API call
      return {
        location,
        temperature: "72°F",
        condition: "Sunny",
      }
    },
  },
}
 
export function WeatherToolBlock() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: "/api/weather-chat",
    tools,
  })
 
  return <div>{/* Chat interface with tool calling */}</div>
}

Human-in-the-Loop Block

import { useChat } from "ai/react"
 
import { Button } from "@/components/ui/button"
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
 
export function HumanInLoopBlock() {
  const { messages, input, handleInputChange, handleSubmit, toolInvocations } =
    useChat({
      api: "/api/human-in-loop",
      tools: {
        weatherTool: {
          description: "Get weather information",
          parameters: z.object({
            location: z.string().describe("City name"),
          }),
          execute: async ({ location }) => {
            // This tool requires human approval
            return { location, temperature: "72°F", condition: "Sunny" }
          },
        },
      },
    })
 
  return (
    <div className="mx-auto max-w-4xl space-y-4">
      {/* Messages */}
      {messages.map((message) => (
        <div key={message.id}>
          <MessageContent>{message.content}</MessageContent>
        </div>
      ))}
 
      {/* Tool invocations requiring approval */}
      {toolInvocations.map((invocation) => (
        <Card key={invocation.toolCallId}>
          <CardHeader>
            <CardTitle>Tool Approval Required</CardTitle>
            <CardDescription>
              The AI wants to execute: {invocation.toolName}
            </CardDescription>
          </CardHeader>
          <CardContent>
            <div className="space-y-2">
              <p>
                <strong>Parameters:</strong>
              </p>
              <pre className="bg-muted rounded p-2 text-sm">
                {JSON.stringify(invocation.args, null, 2)}
              </pre>
              <div className="flex gap-2">
                <Button onClick={() => invocation.result.resolve("approved")}>
                  Approve
                </Button>
                <Button
                  variant="outline"
                  onClick={() => invocation.result.resolve("rejected")}
                >
                  Reject
                </Button>
              </div>
            </div>
          </CardContent>
        </Card>
      ))}
 
      {/* Input form */}
      <form onSubmit={handleSubmit}>
        <PromptInputTextarea
          value={input}
          onChange={handleInputChange}
          placeholder="Ask for weather information..."
        />
        <Button type="submit">Send</Button>
      </form>
    </div>
  )
}

Deployment & Production

Environment Setup

  1. Set up Upstash Redis for rate limiting:

    # Install Upstash CLI
    npm install -g @upstash/cli
     
    # Create Redis database
    upstash redis create my-redis-db
  2. Configure environment variables:

    # .env.local
    OPENAI_API_KEY=your_openai_api_key
    GOOGLE_API_KEY=your_google_api_key
    CLAUDE_API_KEY=your_claude_api_key
     
    # Upstash Redis
    UPSTASH_REDIS_REST_URL=https://your-redis-url.upstash.io
    UPSTASH_REDIS_REST_TOKEN=your_redis_token
     
    # Optional: Vercel AI Gateway
    VERCEL_AI_GATEWAY_URL=https://your-gateway-url.vercel.app
  3. Deploy to Vercel:

    # Install Vercel CLI
    npm install -g vercel
     
    # Deploy
    vercel --prod

Monitoring & Analytics

  • Vercel Analytics: Built-in performance monitoring
  • Upstash Console: Redis usage and rate limiting metrics
  • AI Gateway Analytics: AI provider usage and costs
  • Custom Logging: Implement structured logging for debugging

Cost Optimization

  • Rate limiting: Prevent abuse and control costs
  • Caching: Cache responses to reduce API calls
  • Provider selection: Use cost-effective models when appropriate
  • Monitoring: Track usage patterns and optimize accordingly

Troubleshooting

Common Issues

  1. Rate limit exceeded: Check Upstash Redis configuration
  2. API key errors: Verify environment variables are set correctly
  3. Tool execution failures: Check tool schemas and error handling
  4. Streaming issues: Ensure proper error boundaries and fallbacks

Debug Tips

  • Use browser dev tools to inspect network requests
  • Check server logs for API errors
  • Verify rate limiting headers in responses
  • Test with different input scenarios

Next Steps