AI Tools Registry
Install AI SDK tools into your project with the shadcn CLI. Some tools include UI components to render the result in your chat view.
To learn how to use tools, check out the AI SDK docs.
To add your own tools to the AI Tools Registry, file a PR on our public GitHub repository.
New
Image Generation
Generate images from text prompts
API key required
import { openai } from "@ai-sdk/openai"
import {
tool,
experimental_generateImage as generateImage,
type UIToolInvocation,
type JSONValue,
} from "ai"
import { ImageResultSchema, ImageInputSchema } from "./schema"
import type { ImageResult, ImageItem } from "./schema"
export const imageOpenAITool = tool({
name: "image-openai",
description: "Generate images using OpenAI via Vercel AI SDK (gpt-image-1).",
inputSchema: ImageInputSchema,
outputSchema: ImageResultSchema,
execute: async ({
prompt,
referenceImageUrl,
n,
aspectRatio,
seed,
negativePrompt,
}): Promise<ImageResult> => {
type GenerateImageReturn = Awaited<ReturnType<typeof generateImage>>
type BaseGenerated = NonNullable<GenerateImageReturn["images"]>[number]
type EnhancedGenerated = BaseGenerated & {
url?: string
base64?: string
contentType?: string
width?: number
height?: number
}
type ProviderOptions = NonNullable<
Parameters<typeof generateImage>[0]["providerOptions"]
>
const coerceAspectRatio = (
ar?: string
): `${number}:${number}` | undefined =>
ar && /^\d+:\d+$/.test(ar) ? (ar as `${number}:${number}`) : undefined
const buildProviderOptions = (
np?: unknown
): ProviderOptions | undefined => {
if (typeof np === "string")
return {
negativePrompt: { value: np } as Record<string, JSONValue>,
} as ProviderOptions
if (np && typeof np === "object")
return {
negativePrompt: np as Record<string, JSONValue>,
} as ProviderOptions
return undefined
}
const normalizeImages = (images?: BaseGenerated[] | null): ImageItem[] =>
images?.map((img) => {
const x = img as EnhancedGenerated
return {
url: x.url,
base64: x.base64,
mimeType: (x as { mimeType?: string }).mimeType || x.contentType,
width: x.width,
height: x.height,
}
}) ?? []
const buildImageResult = (params: {
provider: string
prompt: string
images: ImageItem[]
aspectRatio?: string
seed?: number
}): ImageResult => params as ImageResult
const ar = coerceAspectRatio(aspectRatio)
const providerOptions = buildProviderOptions(negativePrompt)
const { images } = await generateImage({
model: openai.image("openai/gpt-image-1"),
prompt,
aspectRatio: ar,
seed,
n,
...(providerOptions ? { providerOptions } : {}),
})
const out = normalizeImages(images)
return buildImageResult({
provider: "openai",
prompt,
images: out,
aspectRatio,
seed,
})
},
})
export type ImageToolType = UIToolInvocation<typeof imageOpenAITool>
Image count
Aspect ratio
Generated Images
“A serene landscape with mountains at sunrise”
demo
Web Search
Search the web and show results
API key required
import { perplexity } from "@ai-sdk/perplexity"
import { tool, generateObject, UIToolInvocation } from "ai"
import { z } from "zod"
import { WebSearchSchema, WebSearchResult } from "./schema"
export const webSearchPerplexityTool = tool({
name: "websearch-perplexity",
description:
"Search the web using Perplexity Sonar via Vercel AI SDK. Requires Perplexity API key. See Vercel docs.",
inputSchema: z.object({
query: z.string().min(1),
limit: z.number().min(1).max(20).default(5),
}),
outputSchema: WebSearchSchema,
execute: async ({ query, limit }) => {
// Use Sonar (or Sonar Pro) for search-grounded results
const { object } = await generateObject({
model: perplexity("sonar"),
schema: WebSearchSchema,
system:
"You are a search assistant. Return strictly the JSON schema provided. For each result include title, url, a short snippet, and a source hostname.",
prompt: `Search the web for: ${query}. Return up to ${limit} high-quality, diverse results with proper URLs.`,
})
// Ensure limit is respected in case the model over-returns
const normalized: WebSearchResult = {
query,
results: (object.results || []).slice(0, limit).map((r) => {
let source = r.source
if (!source) {
try {
source = new URL(r.url).hostname
} catch {
source = undefined
}
}
return { title: r.title, url: r.url, snippet: r.snippet, source }
}),
}
return normalized
},
})
export type WebSearchToolInvocation = UIToolInvocation<
typeof webSearchPerplexityTool
>
Web Search
Query chatgpt- ChatGPT — OpenAIopenai.comChatGPT is a conversational AI model developed by OpenAI that can assist with a wide range of tasks.openai.com
- What is ChatGPT?en.wikipedia.orgChatGPT is a generative artificial intelligence chatbot developed by OpenAI and launched in November 2022.en.wikipedia.org
- Introducing ChatGPTopenai.comWe’ve trained a model called ChatGPT which interacts in a conversational way.openai.com
Public Stats
AI SDK tool that fetches global earthquake counts from USGS and renders a chart.
import { UIToolInvocation, tool } from "ai"
import { z } from "zod"
// Fetch global earthquake counts (per day) from USGS for the last N days
export const StatsSeriesPointSchema = z.object({
date: z.string(),
count: z.number(),
})
export const PublicStatsSchema = z.object({
title: z.string(),
series: z.array(StatsSeriesPointSchema),
})
export type StatsSeriesPoint = z.infer<typeof StatsSeriesPointSchema>
export type PublicStatsResult = z.infer<typeof PublicStatsSchema>
export const publicStatsTool = tool({
name: "stats",
description:
"Fetch daily counts of global earthquakes from USGS for the last N days.",
inputSchema: z.object({
daysBack: z
.number()
.int()
.min(1)
.max(365)
.default(30)
.describe("How many days back from today (UTC) to include"),
minMagnitude: z
.number()
.min(0)
.max(10)
.default(5)
.describe("Minimum magnitude to include"),
}),
outputSchema: PublicStatsSchema,
execute: async ({ daysBack, minMagnitude }): Promise<PublicStatsResult> => {
const end = new Date()
const start = new Date(end.getTime() - daysBack * 24 * 60 * 60 * 1000)
const fmt = (d: Date) => d.toISOString().slice(0, 10)
const params = new URLSearchParams({
format: "geojson",
starttime: fmt(start),
endtime: fmt(end),
minmagnitude: String(minMagnitude),
})
const url = `https://earthquake.usgs.gov/fdsnws/event/1/query?${params.toString()}`
const res = await fetch(url)
if (!res.ok) throw new Error(`USGS API failed: ${res.status}`)
const data = (await res.json()) as {
features?: Array<{ properties?: { time?: number } }>
}
const counts = new Map<string, number>()
for (const f of data.features ?? []) {
const t = f?.properties?.time
if (!Number.isFinite(t)) continue
const day = new Date(Number(t)).toISOString().slice(0, 10)
counts.set(day, (counts.get(day) || 0) + 1)
}
const series: StatsSeriesPoint[] = []
for (let i = daysBack; i >= 0; i--) {
const d = new Date(end.getTime() - i * 24 * 60 * 60 * 1000)
const day = d.toISOString().slice(0, 10)
series.push({ date: day, count: counts.get(day) || 0 })
}
return { title: `Global M${minMagnitude}+ earthquakes`, series }
},
})
export default publicStatsTool
export type StatsToolType = UIToolInvocation<typeof publicStatsTool>
Global M5+ earthquakes
Source: USGS Earthquake Catalog
Get Weather
AI SDK tool that returns mock weather for a location. Includes a WeatherCard renderer.
import { UIToolInvocation, tool } from "ai"
import { z } from "zod"
// Tool definition first
export const GetWeatherSchema = z.object({
location: z.string(),
unit: z.enum(["C", "F"]),
temperature: z.number(),
condition: z.string(),
high: z.number(),
low: z.number(),
humidity: z.number(),
windKph: z.number(),
icon: z.string().optional(),
})
export type GetWeatherResult = z.infer<typeof GetWeatherSchema>
// Tool definition first
export const getWeatherTool = tool({
name: "weather",
description: "Get the current weather for a location.",
inputSchema: z.object({
location: z.string().describe("City name, address or coordinates"),
unit: z.enum(["C", "F"]).default("C"),
}),
outputSchema: GetWeatherSchema,
execute: async ({ location, unit }) => {
const { latitude, longitude, name } = await geocodeLocation(location)
const params = new URLSearchParams({
latitude: String(latitude),
longitude: String(longitude),
current: [
"temperature_2m",
"relative_humidity_2m",
"wind_speed_10m",
"weather_code",
].join(","),
daily: ["temperature_2m_max", "temperature_2m_min"].join(","),
timezone: "auto",
temperature_unit: unit === "F" ? "fahrenheit" : "celsius",
wind_speed_unit: "kmh",
})
const url = `https://api.open-meteo.com/v1/forecast?${params.toString()}`
const res = await fetch(url)
if (!res.ok) throw new Error(`Weather API failed: ${res.status}`)
const data = (await res.json()) as ForecastResponse
const current = data?.current
const daily = data?.daily
if (!current || !daily) throw new Error("Malformed weather API response")
const weatherCode = Number(current.weather_code)
const mapped = mapWeatherCode(weatherCode)
const result: GetWeatherResult = {
location: name,
unit,
temperature: Math.round(Number(current.temperature_2m)),
condition: mapped.condition,
high: Math.round(Number(daily.temperature_2m_max?.[0])),
low: Math.round(Number(daily.temperature_2m_min?.[0])),
humidity: Math.max(
0,
Math.min(1, Number(current.relative_humidity_2m) / 100)
),
windKph: Math.round(Number(current.wind_speed_10m)),
icon: mapped.icon,
}
return result
},
})
// API response types (from Open-Meteo)
interface GeocodeItem {
id: number
name: string
latitude: number
longitude: number
elevation?: number
country_code?: string
admin1?: string
timezone?: string
}
interface GeocodeResponse {
results?: GeocodeItem[]
}
interface ForecastCurrent {
time: string
interval: number
temperature_2m: number
relative_humidity_2m: number
wind_speed_10m: number
weather_code: number
}
interface ForecastDaily {
time: string[]
temperature_2m_max: number[]
temperature_2m_min: number[]
}
interface ForecastResponse {
current: ForecastCurrent
daily: ForecastDaily
}
// Helper functions (hoisted)
async function geocodeLocation(location: string): Promise<{
latitude: number
longitude: number
name: string
}> {
// Allow "lat,lon" inputs without geocoding
const coordMatch = location
.trim()
.match(/^\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*$/)
if (coordMatch) {
const latitude = parseFloat(coordMatch[1])
const longitude = parseFloat(coordMatch[2])
return {
latitude,
longitude,
name: `${latitude.toFixed(3)}, ${longitude.toFixed(3)}`,
}
}
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(
location
)}&count=1&language=en&format=json`
const res = await fetch(url)
if (!res.ok) throw new Error(`Geocoding failed: ${res.status}`)
const data = (await res.json()) as GeocodeResponse
const first = data?.results?.[0]
if (!first) throw new Error(`Location not found: ${location}`)
const nameParts = [first.name, first.admin1, first.country_code].filter(
Boolean
)
return {
latitude: first.latitude,
longitude: first.longitude,
name: nameParts.join(", "),
}
}
function mapWeatherCode(code: number): { condition: string; icon?: string } {
switch (code) {
case 0:
return { condition: "Clear sky", icon: "weather-sun" }
case 1:
return { condition: "Mainly clear", icon: "weather-sun" }
case 2:
return { condition: "Partly cloudy", icon: "weather-partly" }
case 3:
return { condition: "Overcast", icon: "weather-cloud" }
case 45:
case 48:
return { condition: "Fog", icon: "weather-fog" }
case 51:
case 53:
case 55:
case 56:
case 57:
return { condition: "Drizzle", icon: "weather-drizzle" }
case 61:
case 63:
case 65:
case 66:
case 67:
return { condition: "Rain", icon: "weather-rain" }
case 71:
case 73:
case 75:
case 77:
return { condition: "Snow", icon: "weather-snow" }
case 80:
case 81:
case 82:
return { condition: "Showers", icon: "weather-showers" }
case 85:
case 86:
return { condition: "Snow showers", icon: "weather-snow" }
case 95:
case 96:
case 99:
return { condition: "Thunderstorm", icon: "weather-thunder" }
default:
return { condition: "Unknown" }
}
}
export type WeatherToolType = UIToolInvocation<typeof getWeatherTool>
Weather
San Francisco
weather-sun
Current conditions
21°C
Sunny
High 24°C • Low 18°C
- Humidity
- 45%
- Wind
- 8 kph
News Search
Return recent headlines for a topic (mock). Includes a NewsList renderer.
import { UIToolInvocation, tool } from "ai"
import { z } from "zod"
export const NewsItemSchema = z.object({
id: z.string(),
title: z.string(),
url: z.string().url().optional(),
publishedAt: z.string().optional(),
})
export const NewsSearchSchema = z.object({
topic: z.string(),
items: z.array(NewsItemSchema),
})
// Tool first
export const newsSearchTool = tool({
name: "news",
description: "Return recent headlines related to a topic.",
inputSchema: z.object({
topic: z.string().min(1),
limit: z.number().min(1).max(20).default(5),
}),
outputSchema: NewsSearchSchema,
execute: async ({ topic, limit }) => {
// Use Hacker News Algolia Search API (no API key required)
const url = `https://hn.algolia.com/api/v1/search?${new URLSearchParams({
query: topic,
tags: "story",
hitsPerPage: String(limit),
}).toString()}`
const res = await fetch(url)
if (!res.ok) throw new Error(`News API failed: ${res.status}`)
const data = (await res.json()) as AlgoliaSearchResponse
const items: NewsItem[] = (data.hits || []).map((h) => ({
id: String(h.objectID),
title: h.title || h.story_title || "(untitled)",
url: h.url || h.story_url || undefined,
publishedAt: h.created_at || undefined,
}))
return { topic, items }
},
})
// Public result shapes for UI
export type NewsItem = z.infer<typeof NewsItemSchema>
export type NewsSearchResult = z.infer<typeof NewsSearchSchema>
// Response types from Algolia API
interface AlgoliaHit {
objectID: string
title?: string
story_title?: string
url?: string
story_url?: string
created_at?: string
}
interface AlgoliaSearchResponse {
hits: AlgoliaHit[]
}
export type NewsToolType = UIToolInvocation<typeof newsSearchTool>
News
Latest on AI- Tooling ecosystem expands
QR Code Generator
AI SDK tool that generates QR codes for text or URLs. Includes a QR code display component.
import { UIToolInvocation, tool } from "ai"
import { z } from "zod"
import QRCode from "qrcode"
export const QRCodeSchema = z.object({
data: z.string(),
size: z.number(),
output: z.string(),
})
export type QRCodeResult = z.infer<typeof QRCodeSchema>
export const qrCodeTool = tool({
name: "qrcode",
description: "Generate QR codes for text, URLs, or other data.",
inputSchema: z.object({
data: z
.string()
.min(1)
.describe("The text or URL to encode in the QR code"),
size: z
.number()
.min(100)
.max(500)
.default(300)
.describe("Size of the QR code in pixels"),
}),
outputSchema: QRCodeSchema,
execute: async ({ data, size }) => {
const output = await QRCode.toDataURL(data, {
width: size,
margin: 4,
})
const result: QRCodeResult = {
data,
size,
output,
}
return result
},
})
export type QRCodeToolType = UIToolInvocation<typeof qrCodeTool>
QR Code
https://ai-tools-registry.vercel.app
All Tools
Image Generation
AI SDK tool that generates images from text prompts. Includes a grid renderer.
Image Generation (Gemini)
Generate images using Google Gemini via Vercel AI SDK. Shares renderer.
Web Search (Perplexity)
Web search via Perplexity Sonar using Vercel AI SDK (requires Perplexity API key). Shares renderer.
Web Search (Firecrawl)
Web search via Firecrawl API (requires FIRECRAWL_API_KEY). Shares renderer.
Web Search (Brave)
Web search via Brave Search API (requires BRAVE_SEARCH_API_KEY). Shares renderer.