Vercel AI SDK Integration¶
This document provides comprehensive documentation for the Vercel AI SDK integration in the Inttrest platform, covering implementation details, configuration, and best practices.
๐ค Overview¶
The Vercel AI SDK is the core AI framework powering Inttrest's intelligent event discovery capabilities. It provides a seamless way to integrate AI-powered features including natural language processing, intelligent search, and conversational interfaces.
graph TB
subgraph "AI SDK Architecture"
A[Vercel AI SDK Core] --> B[React Hooks]
A --> C[OpenAI Provider]
A --> D[Stream Processing]
B --> E[useChat Hook]
B --> F[useCompletion Hook]
B --> G[useAssistant Hook]
C --> H[GPT Models]
C --> I[Function Calling]
C --> J[Structured Output]
D --> K[Real-time Streaming]
D --> L[Message Processing]
D --> M[State Management]
end
subgraph "Application Integration"
N[Chat Interface] --> E
O[Event Search] --> F
P[AI Assistant] --> G
Q[Event Discovery] --> I
R[Location Processing] --> J
S[User Interaction] --> K
end
style A fill:#e3f2fd
style N fill:#e8f5e8
style Q fill:#fff3e0
๐ฆ Dependencies¶
The AI SDK integration uses the following key packages:
{
"dependencies": {
"ai": "^5.0.28",
"@ai-sdk/openai": "^2.0.23",
"@ai-sdk/react": "^2.0.28",
"zod": "^4.1.5"
}
}
Package Details¶
| Package | Version | Purpose |
|---|---|---|
ai |
^5.0.28 | Core AI SDK with utilities and providers |
@ai-sdk/openai |
^2.0.23 | OpenAI provider for the AI SDK |
@ai-sdk/react |
^2.0.28 | React hooks and components |
zod |
^4.1.5 | Schema validation for structured outputs |
๐ ๏ธ Core Implementation¶
AI Provider Configuration¶
// lib/ai-config.ts
import { openai } from '@ai-sdk/openai'
import { experimental_wrapLanguageModel as wrapLanguageModel } from 'ai'
// Configure OpenAI provider
export const aiModel = wrapLanguageModel({
model: openai('gpt-4-turbo-preview'),
middleware: {
transformParams: async ({ params }) => {
return {
...params,
temperature: 0.7,
max_tokens: 1000,
top_p: 0.9,
}
}
}
})
// Event discovery specific model
export const eventDiscoveryModel = openai('gpt-4-turbo-preview', {
structuredOutputs: true,
})
// Configuration constants
export const AI_CONFIG = {
models: {
chat: 'gpt-4-turbo-preview',
completion: 'gpt-3.5-turbo',
embedding: 'text-embedding-3-small'
},
limits: {
maxTokens: 1000,
temperature: 0.7,
topP: 0.9
},
features: {
streaming: true,
functionCalling: true,
structuredOutput: true
}
} as const
Chat API Implementation¶
// app/api/chat/route.ts
import { streamText, convertToCoreMessages } from 'ai'
import { aiModel } from '@/lib/ai-config'
import { z } from 'zod'
// Define schemas for structured outputs
const EventSearchSchema = z.object({
location: z.string().optional(),
category: z.string().optional(),
dateRange: z.object({
start: z.string().optional(),
end: z.string().optional()
}).optional(),
keywords: z.array(z.string()).optional()
})
const EventActionSchema = z.object({
action: z.enum(['search', 'filter', 'recommend', 'details']),
parameters: EventSearchSchema
})
export async function POST(req: Request) {
try {
const { messages } = await req.json()
const result = await streamText({
model: aiModel,
messages: convertToCoreMessages(messages),
system: `You are an intelligent event discovery assistant for Inttrest.
Your role is to help users find and discover events based on their preferences. You can:
1. Search for events by location, category, date, or keywords
2. Provide personalized recommendations
3. Filter and sort events based on user criteria
4. Explain event details and help with planning
When users ask about events, try to understand their intent and provide helpful, actionable responses.
If you need to perform an action like searching or filtering events, use the available tools.
Current capabilities:
- Search events across multiple platforms (Eventbrite, Meetup, LinkedIn, Instagram)
- Filter by location, category, date range, and other criteria
- Provide intelligent recommendations based on user preferences
- Help with event planning and discovery
Be conversational, helpful, and proactive in suggesting relevant events.`,
tools: {
searchEvents: {
description: 'Search for events based on user criteria',
parameters: EventSearchSchema,
execute: async (params) => {
// Implementation for event search
return await searchEventsWithCriteria(params)
}
},
filterEvents: {
description: 'Filter existing events based on criteria',
parameters: EventSearchSchema,
execute: async (params) => {
// Implementation for event filtering
return await filterEventsWithCriteria(params)
}
},
getEventRecommendations: {
description: 'Get personalized event recommendations',
parameters: z.object({
userPreferences: z.array(z.string()),
location: z.string().optional()
}),
execute: async (params) => {
// Implementation for recommendations
return await getPersonalizedRecommendations(params)
}
}
},
maxTokens: 1000,
temperature: 0.7,
})
return result.toAIStreamResponse()
} catch (error) {
console.error('Chat API error:', error)
return new Response('Internal Server Error', { status: 500 })
}
}
// Helper functions for tool execution
async function searchEventsWithCriteria(params: z.infer<typeof EventSearchSchema>) {
// Connect to MCP servers and search for events
const searchResults = await fetch('/api/events/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params)
})
return await searchResults.json()
}
async function filterEventsWithCriteria(params: z.infer<typeof EventSearchSchema>) {
// Filter events from current dataset
const filterResults = await fetch('/api/events/filter', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params)
})
return await filterResults.json()
}
async function getPersonalizedRecommendations(params: any) {
// Get AI-powered recommendations
const recommendations = await fetch('/api/events/recommendations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params)
})
return await recommendations.json()
}
React Integration with useChat Hook¶
// components/Chat.tsx
'use client'
import { useChat } from 'ai/react'
import { useState, useRef, useEffect } from 'react'
import { Send, Bot, User, Loader2 } from 'lucide-react'
interface ChatProps {
onEventAction?: (action: string, params: any) => void
}
export default function Chat({ onEventAction }: ChatProps) {
const {
messages,
input,
handleInputChange,
handleSubmit,
isLoading,
error,
append,
reload,
stop
} = useChat({
api: '/api/chat',
onFinish: (message) => {
// Handle completion of AI response
handleAIResponse(message)
},
onError: (error) => {
console.error('Chat error:', error)
}
})
const messagesEndRef = useRef<HTMLDivElement>(null)
const [suggestions] = useState([
"Find tech events in San Francisco this week",
"Show me networking events near me",
"What business conferences are happening in New York?",
"Find free events this weekend",
"Recommend events based on my interests"
])
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
}
useEffect(() => {
scrollToBottom()
}, [messages])
const handleAIResponse = (message: any) => {
// Parse AI response for actions
if (message.toolInvocations) {
message.toolInvocations.forEach((invocation: any) => {
switch (invocation.toolName) {
case 'searchEvents':
onEventAction?.('search', invocation.args)
break
case 'filterEvents':
onEventAction?.('filter', invocation.args)
break
case 'getEventRecommendations':
onEventAction?.('recommend', invocation.args)
break
}
})
}
}
const handleSuggestionClick = (suggestion: string) => {
append({ role: 'user', content: suggestion })
}
return (
<div className="flex flex-col h-full bg-white rounded-lg shadow-sm border">
{/* Chat Header */}
<div className="flex items-center justify-between p-4 border-b bg-blue-50">
<div className="flex items-center space-x-2">
<Bot className="w-6 h-6 text-blue-600" />
<div>
<h3 className="font-semibold text-gray-900">AI Event Assistant</h3>
<p className="text-sm text-gray-600">Discover events with AI</p>
</div>
</div>
{isLoading && (
<button
onClick={stop}
className="p-2 text-gray-500 hover:text-red-500 transition-colors"
title="Stop generation"
>
<Loader2 className="w-4 h-4 animate-spin" />
</button>
)}
</div>
{/* Messages Container */}
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.length === 0 && (
<div className="text-center py-8">
<Bot className="w-12 h-12 text-blue-400 mx-auto mb-4" />
<h4 className="text-lg font-medium text-gray-900 mb-2">
Welcome to AI Event Discovery
</h4>
<p className="text-gray-600 mb-6">
Ask me anything about events! I can help you find, filter, and discover events based on your preferences.
</p>
{/* Suggestion Pills */}
<div className="flex flex-wrap gap-2 justify-center">
{suggestions.map((suggestion, index) => (
<button
key={index}
onClick={() => handleSuggestionClick(suggestion)}
className="px-3 py-1 text-sm bg-blue-100 text-blue-700 rounded-full hover:bg-blue-200 transition-colors"
>
{suggestion}
</button>
))}
</div>
</div>
)}
{messages.map((message) => (
<div
key={message.id}
className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-xs lg:max-w-md px-4 py-3 rounded-lg ${
message.role === 'user'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-900'
}`}
>
<div className="flex items-center space-x-2 mb-1">
{message.role === 'user' ? (
<User className="w-4 h-4" />
) : (
<Bot className="w-4 h-4" />
)}
<span className="text-sm font-medium">
{message.role === 'user' ? 'You' : 'AI Assistant'}
</span>
</div>
<div className="text-sm whitespace-pre-wrap">
{message.content}
</div>
{/* Display tool invocations */}
{message.toolInvocations && (
<div className="mt-2 space-y-1">
{message.toolInvocations.map((invocation: any, index: number) => (
<div key={index} className="text-xs opacity-75">
๐ง {invocation.toolName}: {JSON.stringify(invocation.args)}
</div>
))}
</div>
)}
</div>
</div>
))}
{error && (
<div className="flex justify-center">
<div className="bg-red-100 border border-red-300 text-red-700 px-4 py-2 rounded-lg">
<p className="text-sm">Error: {error.message}</p>
<button
onClick={reload}
className="text-red-600 hover:text-red-800 text-sm underline mt-1"
>
Try again
</button>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
{/* Input Form */}
<div className="border-t p-4">
<form onSubmit={handleSubmit} className="flex space-x-3">
<input
value={input}
onChange={handleInputChange}
placeholder="Ask about events..."
disabled={isLoading}
className="flex-1 border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100"
/>
<button
type="submit"
disabled={!input.trim() || isLoading}
className="bg-blue-600 text-white p-2 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
>
{isLoading ? (
<Loader2 className="w-5 h-5 animate-spin" />
) : (
<Send className="w-5 h-5" />
)}
</button>
</form>
</div>
</div>
)
}
๐ง AI-Powered Features¶
Intelligent Event Search¶
The AI SDK enables natural language event search with intelligent parameter extraction:
// lib/ai-search.ts
import { generateObject } from 'ai'
import { eventDiscoveryModel } from './ai-config'
import { z } from 'zod'
const SearchParametersSchema = z.object({
location: z.string().optional().describe('Geographic location for events'),
category: z.string().optional().describe('Event category (tech, business, networking, etc.)'),
dateRange: z.object({
start: z.string().optional().describe('Start date in ISO format'),
end: z.string().optional().describe('End date in ISO format')
}).optional(),
keywords: z.array(z.string()).optional().describe('Keywords to search for'),
priceRange: z.object({
min: z.number().optional(),
max: z.number().optional()
}).optional(),
eventType: z.enum(['online', 'in-person', 'hybrid']).optional(),
interests: z.array(z.string()).optional().describe('User interests and preferences')
})
export async function parseSearchQuery(query: string): Promise<z.infer<typeof SearchParametersSchema>> {
const { object } = await generateObject({
model: eventDiscoveryModel,
schema: SearchParametersSchema,
prompt: `Parse this natural language event search query and extract relevant parameters: "${query}"
Examples:
- "tech events in San Francisco this week" โ location: "San Francisco", category: "tech", dateRange with this week
- "free networking events near me" โ category: "networking", priceRange: {max: 0}, location: user location
- "business conferences in New York next month" โ category: "business", location: "New York", dateRange: next month
Be smart about interpreting relative dates, informal location names, and implied preferences.`
})
return object
}
export async function generateEventRecommendations(userProfile: any, events: any[]) {
const RecommendationSchema = z.object({
recommendations: z.array(z.object({
eventId: z.string(),
score: z.number().min(0).max(1),
reasons: z.array(z.string()),
category: z.string()
})),
insights: z.array(z.string()).describe('Insights about user preferences')
})
const { object } = await generateObject({
model: eventDiscoveryModel,
schema: RecommendationSchema,
prompt: `Based on this user profile and available events, generate personalized recommendations:
User Profile: ${JSON.stringify(userProfile)}
Available Events: ${JSON.stringify(events.slice(0, 20))} // Limit for context
Provide a score (0-1) for each recommended event and explain why it matches the user's interests.
Consider factors like location preferences, past event attendance, interests, and career goals.`
})
return object
}
Structured Event Data Processing¶
// lib/ai-processing.ts
import { generateObject } from 'ai'
import { eventDiscoveryModel } from './ai-config'
import { z } from 'zod'
const EventEnrichmentSchema = z.object({
enhancedDescription: z.string().describe('AI-enhanced event description'),
tags: z.array(z.string()).describe('Relevant tags for the event'),
targetAudience: z.array(z.string()).describe('Target audience segments'),
skillLevel: z.enum(['beginner', 'intermediate', 'advanced', 'all']).describe('Required skill level'),
networking: z.boolean().describe('Whether this is primarily a networking event'),
learningOutcomes: z.array(z.string()).describe('What attendees will learn'),
industry: z.array(z.string()).describe('Relevant industries'),
format: z.enum(['workshop', 'conference', 'meetup', 'webinar', 'hackathon', 'panel', 'other']),
sentiment: z.object({
excitement: z.number().min(0).max(1),
professionalism: z.number().min(0).max(1),
accessibility: z.number().min(0).max(1)
})
})
export async function enrichEventData(eventData: any) {
const { object } = await generateObject({
model: eventDiscoveryModel,
schema: EventEnrichmentSchema,
prompt: `Analyze this event and provide enriched metadata:
Event Data: ${JSON.stringify(eventData)}
Provide structured insights that will help users understand what this event offers,
who should attend, and what they can expect to gain from it.`
})
return object
}
export async function categorizeEvent(eventData: any) {
const CategorySchema = z.object({
primaryCategory: z.enum([
'technology', 'business', 'networking', 'education', 'entertainment',
'sports', 'health', 'arts', 'food', 'travel', 'other'
]),
secondaryCategories: z.array(z.string()),
confidence: z.number().min(0).max(1),
reasoning: z.string()
})
const { object } = await generateObject({
model: eventDiscoveryModel,
schema: CategorySchema,
prompt: `Categorize this event based on its content and context:
Event: ${JSON.stringify(eventData)}
Determine the most appropriate primary category and any relevant secondary categories.
Provide a confidence score and explain your reasoning.`
})
return object
}
โก Performance Optimization¶
Streaming Responses¶
The AI SDK provides built-in streaming capabilities for better user experience:
// components/StreamingChat.tsx
import { useChat } from 'ai/react'
import { useEffect, useState } from 'react'
export function StreamingChat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
api: '/api/chat',
streamMode: 'stream-data', // Enable streaming
onFinish: (message, { usage, finishReason }) => {
console.log('Completion finished:', { usage, finishReason })
}
})
return (
<div className="chat-container">
{messages.map((message) => (
<div key={message.id} className={`message ${message.role}`}>
{/* Render streaming content as it arrives */}
<div className="content">
{message.content}
</div>
{/* Show typing indicator for assistant messages being streamed */}
{message.role === 'assistant' && isLoading && (
<div className="typing-indicator">
<span className="dot"></span>
<span className="dot"></span>
<span className="dot"></span>
</div>
)}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={handleInputChange}
placeholder="Type your message..."
disabled={isLoading}
/>
<button type="submit" disabled={isLoading}>
Send
</button>
</form>
</div>
)
}
Caching and Rate Limiting¶
// lib/ai-cache.ts
import { LRUCache } from 'lru-cache'
interface CacheEntry {
result: any
timestamp: number
ttl: number
}
class AICache {
private cache: LRUCache<string, CacheEntry>
constructor(maxSize = 1000, defaultTTL = 1000 * 60 * 15) { // 15 minutes
this.cache = new LRUCache({
max: maxSize,
ttl: defaultTTL
})
}
generateKey(input: any): string {
return JSON.stringify(input)
}
get(key: string): any | null {
const entry = this.cache.get(key)
if (!entry) return null
const now = Date.now()
if (now - entry.timestamp > entry.ttl) {
this.cache.delete(key)
return null
}
return entry.result
}
set(key: string, result: any, ttl?: number): void {
this.cache.set(key, {
result,
timestamp: Date.now(),
ttl: ttl || 1000 * 60 * 15
})
}
async getOrCompute<T>(
key: string,
computeFn: () => Promise<T>,
ttl?: number
): Promise<T> {
const cached = this.get(key)
if (cached) return cached
const result = await computeFn()
this.set(key, result, ttl)
return result
}
}
export const aiCache = new AICache()
// Usage in API routes
export async function cachedGenerateObject(params: any) {
const cacheKey = aiCache.generateKey(params)
return await aiCache.getOrCompute(
cacheKey,
() => generateObject(params),
1000 * 60 * 30 // 30 minutes for AI generation
)
}
๐ง Configuration & Environment¶
Environment Variables¶
# .env.local
OPENAI_API_KEY=sk-your-openai-api-key-here
AI_SDK_LOG_LEVEL=info
AI_CACHE_TTL=900000
AI_MAX_TOKENS=1000
AI_TEMPERATURE=0.7
AI_MODEL_CHAT=gpt-4-turbo-preview
AI_MODEL_COMPLETION=gpt-3.5-turbo
AI_MODEL_EMBEDDING=text-embedding-3-small
Runtime Configuration¶
// lib/config.ts
export const aiConfig = {
openai: {
apiKey: process.env.OPENAI_API_KEY!,
baseURL: process.env.OPENAI_BASE_URL,
organization: process.env.OPENAI_ORG_ID,
},
models: {
chat: process.env.AI_MODEL_CHAT || 'gpt-4-turbo-preview',
completion: process.env.AI_MODEL_COMPLETION || 'gpt-3.5-turbo',
embedding: process.env.AI_MODEL_EMBEDDING || 'text-embedding-3-small',
},
limits: {
maxTokens: parseInt(process.env.AI_MAX_TOKENS || '1000'),
temperature: parseFloat(process.env.AI_TEMPERATURE || '0.7'),
topP: parseFloat(process.env.AI_TOP_P || '0.9'),
},
cache: {
ttl: parseInt(process.env.AI_CACHE_TTL || '900000'), // 15 minutes
maxSize: parseInt(process.env.AI_CACHE_MAX_SIZE || '1000'),
},
features: {
streaming: process.env.AI_STREAMING !== 'false',
functionCalling: process.env.AI_FUNCTION_CALLING !== 'false',
structuredOutput: process.env.AI_STRUCTURED_OUTPUT !== 'false',
}
} as const
// Validation
if (!aiConfig.openai.apiKey) {
throw new Error('OPENAI_API_KEY environment variable is required')
}
๐งช Testing AI Features¶
Unit Testing¶
// __tests__/ai/search.test.ts
import { parseSearchQuery, generateEventRecommendations } from '@/lib/ai-search'
import { describe, it, expect, vi } from 'vitest'
describe('AI Search Functions', () => {
it('should parse natural language search queries', async () => {
const query = "tech events in San Francisco this week"
const result = await parseSearchQuery(query)
expect(result.location).toBe("San Francisco")
expect(result.category).toBe("tech")
expect(result.dateRange).toBeDefined()
})
it('should generate relevant event recommendations', async () => {
const userProfile = {
interests: ['technology', 'AI', 'startups'],
location: 'San Francisco',
experience: 'senior'
}
const events = [
{ id: '1', title: 'AI Conference 2024', category: 'tech' },
{ id: '2', title: 'Cooking Class', category: 'food' }
]
const recommendations = await generateEventRecommendations(userProfile, events)
expect(recommendations.recommendations).toHaveLength(2)
expect(recommendations.recommendations[0].score).toBeGreaterThan(
recommendations.recommendations[1].score
)
})
})
Integration Testing¶
// __tests__/api/chat.test.ts
import { POST } from '@/app/api/chat/route'
import { NextRequest } from 'next/server'
describe('/api/chat', () => {
it('should handle event search requests', async () => {
const request = new NextRequest('http://localhost:3000/api/chat', {
method: 'POST',
body: JSON.stringify({
messages: [
{ role: 'user', content: 'Find tech events in San Francisco' }
]
})
})
const response = await POST(request)
expect(response.status).toBe(200)
expect(response.headers.get('content-type')).toContain('text/plain')
})
})
๐ Monitoring & Analytics¶
Usage Tracking¶
// lib/ai-analytics.ts
interface AIUsageMetrics {
requestCount: number
tokenUsage: {
prompt: number
completion: number
total: number
}
responseTime: number
cacheHitRate: number
}
class AIAnalytics {
private metrics: Map<string, AIUsageMetrics> = new Map()
trackRequest(
endpoint: string,
tokenUsage: any,
responseTime: number,
cacheHit: boolean
) {
const current = this.metrics.get(endpoint) || {
requestCount: 0,
tokenUsage: { prompt: 0, completion: 0, total: 0 },
responseTime: 0,
cacheHitRate: 0
}
current.requestCount++
current.tokenUsage.prompt += tokenUsage.promptTokens || 0
current.tokenUsage.completion += tokenUsage.completionTokens || 0
current.tokenUsage.total += tokenUsage.totalTokens || 0
current.responseTime = (current.responseTime + responseTime) / 2
if (cacheHit) {
current.cacheHitRate = (current.cacheHitRate + 1) / current.requestCount
}
this.metrics.set(endpoint, current)
}
getMetrics(endpoint?: string) {
if (endpoint) {
return this.metrics.get(endpoint)
}
return Object.fromEntries(this.metrics)
}
exportMetrics() {
return {
timestamp: new Date().toISOString(),
metrics: this.getMetrics()
}
}
}
export const aiAnalytics = new AIAnalytics()
๐ Best Practices¶
1. Prompt Engineering¶
// lib/prompts.ts
export const SYSTEM_PROMPTS = {
eventDiscovery: `You are an expert event discovery assistant with deep knowledge of:
- Event platforms (Eventbrite, Meetup, LinkedIn Events, etc.)
- Geographic locations and venues
- Event categories and industry trends
- User preferences and behavior patterns
Your goal is to help users find the most relevant events based on their needs.
Always be helpful, accurate, and proactive in suggesting alternatives.`,
eventCategorization: `Analyze event content and categorize accurately.
Consider the event title, description, venue, organizer, and other metadata.
Use consistent categorization that helps users filter and discover events effectively.`,
eventRecommendation: `Provide personalized event recommendations based on:
- User's expressed interests and preferences
- Past event attendance (if available)
- Geographic proximity and convenience
- Event quality and relevance
- Networking opportunities and career growth potential`
}
2. Error Handling¶
// lib/ai-error-handling.ts
export class AIError extends Error {
constructor(
message: string,
public code: string,
public originalError?: Error
) {
super(message)
this.name = 'AIError'
}
}
export async function withErrorHandling<T>(
operation: () => Promise<T>,
context: string
): Promise<T> {
try {
return await operation()
} catch (error) {
if (error instanceof Error) {
// Log error for monitoring
console.error(`AI operation failed in ${context}:`, error)
// Categorize error type
if (error.message.includes('rate limit')) {
throw new AIError(
'AI service is temporarily unavailable due to rate limiting',
'RATE_LIMITED',
error
)
}
if (error.message.includes('timeout')) {
throw new AIError(
'AI service request timed out',
'TIMEOUT',
error
)
}
// Generic error
throw new AIError(
'AI service encountered an error',
'GENERAL_ERROR',
error
)
}
throw error
}
}
3. Performance Optimization¶
// lib/ai-optimization.ts
export function optimizePrompt(prompt: string): string {
// Remove excessive whitespace
let optimized = prompt.replace(/\s+/g, ' ').trim()
// Truncate if too long (keep under token limits)
const maxLength = 4000 // Approximately 1000 tokens
if (optimized.length > maxLength) {
optimized = optimized.substring(0, maxLength) + '...'
}
return optimized
}
export function batchRequests<T>(
items: T[],
batchSize: number = 5
): T[][] {
const batches: T[][] = []
for (let i = 0; i < items.length; i += batchSize) {
batches.push(items.slice(i, i + batchSize))
}
return batches
}
This comprehensive documentation covers the Vercel AI SDK integration in Inttrest, providing developers with everything they need to understand, implement, and maintain the AI-powered features! ๐ค