Using the AI SDK — Agentuity Documentation

Using the AI SDK

Generate text, structured data, and streams with the Vercel AI SDK

The Vercel AI SDK provides a consistent API for LLM interactions with built-in streaming, structured output, and tool calling.

Agentuity works with any approach. This page documents the AI SDK path specifically, and AI SDK is optional. You can also use provider SDKs directly (Anthropic, OpenAI), or frameworks like Mastra and LangGraph. See Using the AI Gateway for examples with different libraries.

Installation

Install the AI SDK and your preferred provider:

bun add ai @ai-sdk/openai

Or with multiple providers:

bun add ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google

Generating Text

Use generateText for simple completions:

import { createAgent } from '@agentuity/runtime';
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
 
const agent = createAgent('TextGenerator', {
  schema: {
    input: z.object({ prompt: z.string() }),
    output: z.object({ response: z.string() }),
  },
  handler: async (ctx, input) => {
    const { text } = await generateText({
      model: openai('gpt-5-mini'),
      prompt: input.prompt,
    });
 
    return { response: text };
  },
});
 
export default agent;

With System Prompt

Add context with a system message:

// Inside your handler:
const { text } = await generateText({
  model: openai('gpt-5-mini'),
  system: 'You are a concise technical assistant. Keep responses under 100 words.',
  prompt: input.prompt,
});

With Message History

Pass conversation history for multi-turn interactions:

// Inside your handler:
const { text } = await generateText({
  model: openai('gpt-5-mini'),
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'What is TypeScript?' },
    { role: 'assistant', content: 'TypeScript is a typed superset of JavaScript.' },
    { role: 'user', content: input.followUp },
  ],
});

Generating Structured Data

Use generateObject to get validated, typed responses:

import { createAgent } from '@agentuity/runtime';
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
 
const SentimentSchema = z.object({
  sentiment: z.enum(['positive', 'negative', 'neutral']),
  confidence: z.number().min(0).max(1),
  keywords: z.array(z.string()),
});
 
const agent = createAgent('SentimentAnalyzer', {
  schema: {
    input: z.object({ text: z.string() }),
    output: SentimentSchema,
  },
  handler: async (ctx, input) => {
    const { object } = await generateObject({
      model: openai('gpt-5-mini'),
      schema: SentimentSchema,
      prompt: `Analyze the sentiment of: "${input.text}"`,
    });
 
    // Schema match means no runtime type assertion needed
    return object;
  },
});
 
export default agent;

Using .describe() for Field Hints

Add .describe() to schema fields to guide the model on format and content:

import { createAgent } from '@agentuity/runtime';
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
 
const EventSchema = z.object({
  title: z.string().describe('Event title, e.g. "Team standup"'),
  date: z.string().describe('ISO 8601 date: YYYY-MM-DD'),
  startTime: z.string().describe('24-hour format: HH:MM'),
  duration: z.number().describe('Duration in minutes'),
  attendees: z.array(z.string()).describe('List of attendee names'),
});
 
const agent = createAgent('EventExtractor', {
  schema: {
    input: z.object({ text: z.string() }),
    output: EventSchema,
  },
  handler: async (ctx, input) => {
    const { object } = await generateObject({
      model: openai('gpt-5-mini'),
      schema: EventSchema,
      prompt: `Extract event details from: "${input.text}"`,
    });
 
    return object;
  },
});
 
export default agent;

The .describe() hints improve output consistency, especially for dates, times, and formatted strings.

Generating Streams

Use streamText for real-time responses:

import { createAgent } from '@agentuity/runtime';
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
 
const agent = createAgent('StreamingChat', {
  schema: {
    input: z.object({ prompt: z.string() }),
    stream: true,
  },
  handler: async (ctx, input) => {
    const { textStream } = streamText({
      model: openai('gpt-5-mini'),
      prompt: input.prompt,
    });
 
    return textStream;
  },
});
 
export default agent;

For detailed streaming patterns, see Streaming Responses.

Switching Providers

Change providers by swapping the import and model:

// OpenAI
import { openai } from '@ai-sdk/openai';
const model = openai('gpt-5-mini');
 
// Anthropic
import { anthropic } from '@ai-sdk/anthropic';
const model = anthropic('claude-sonnet-4-5');
 
// Google
import { google } from '@ai-sdk/google';
const model = google('gemini-2.5-flash');
 
// Groq (fast inference)
import { groq } from '@ai-sdk/groq';
const model = groq('llama-3.3-70b-versatile');

Error Handling

Wrap LLM calls in try-catch to handle errors gracefully:

import { createAgent } from '@agentuity/runtime';
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
 
const agent = createAgent('SafeGenerator', {
  schema: {
    input: z.object({ prompt: z.string() }),
    output: z.object({ response: z.string() }),
  },
  handler: async (ctx, input) => {
    try {
      const { text } = await generateText({
        model: openai('gpt-5-mini'),
        prompt: input.prompt,
      });
 
      return { response: text };
    } catch (error) {
      ctx.logger.error('LLM request failed', { error });
      return { response: 'I encountered an error processing your request.' };
    }
  },
});
 
export default agent;

Best Practices

  • Define output schemas with Zod, Valibot, or ArkType for type safety and validation
  • Add system prompts to guide model behavior consistently
  • Handle errors gracefully with fallback responses

Next Steps