Skip to main content
The @packages/agent package provides a powerful SDK for building AI agents with Convex, built on top of Vercel’s AI SDK.

Installation

npm install @packages/agent

Overview

This package provides:
  • Agent class for managing AI conversations
  • Thread management for conversation history
  • Message storage in Convex
  • Tool integration for function calling
  • Streaming support for real-time responses
  • Context management with RAG (Retrieval Augmented Generation)
  • React hooks for UI integration

Quick Start

import { Agent } from "@packages/agent";
import { openai } from "@ai-sdk/openai";
import { components } from "./convex/_generated/api";

const agent = new Agent(components.agent, {
  name: "my-agent",
  languageModel: openai.chat("gpt-4o"),
  instructions: "You are a helpful assistant.",
});

Core Concepts

Agent Class

The Agent class is the main entry point for building AI agents:
component
AgentComponent
required
The Convex agent component for data persistence
options
Config
required
Configuration options for the agent
name
string
required
Name of the agent (attributed to messages)
languageModel
LanguageModel
required
AI SDK language model (e.g., openai.chat("gpt-4o"))
instructions
string
System prompt for the agent
tools
ToolSet
Tools the agent can use
stopWhen
StopCondition
Conditions for stopping generation

Creating a Thread

Threads represent conversation sessions:
import { action } from "./_generated/server";

export const startConversation = action(async (ctx) => {
  const { threadId, thread } = await agent.createThread(ctx, {
    userId: "user_123",
    title: "My Conversation",
  });
  
  // Use the thread for generation
  const result = await thread.generateText({
    prompt: "Hello, how are you?",
  });
  
  return { threadId, response: result.text };
});
createThread
method
Create a new conversation thread
userId
string
User ID to associate with the thread
title
string
Thread title
summary
string
Thread summary
Returns: { threadId: string, thread: Thread }

Continuing a Thread

export const continueConversation = action(async (ctx, { threadId }) => {
  const { thread } = await agent.continueThread(ctx, { threadId });
  
  const result = await thread.generateText({
    prompt: "Tell me more about that.",
  });
  
  return result.text;
});

Text Generation

Generate Text

Generate text synchronously (waits for complete response):
const result = await agent.generateText(ctx, 
  { threadId, userId },
  {
    prompt: "What is the capital of France?",
    maxSteps: 3,
  }
);

console.log(result.text); // "Paris is the capital of France."
console.log(result.usage); // Token usage stats
generateText
method
Generate text synchronously
prompt
string | ModelMessage[]
required
The user prompt or messages
maxSteps
number
Maximum number of tool call steps
system
string
Override system instructions
Returns: GenerateTextResult with text, usage, finishReason

Stream Text

Stream text for real-time responses:
const stream = await agent.streamText(ctx,
  { threadId, userId },
  {
    prompt: "Write a story about a robot.",
  },
  {
    saveStreamDeltas: true, // Save streaming chunks to DB
  }
);

// Stream to client
for await (const chunk of stream.textStream) {
  console.log(chunk);
}

const fullText = await stream.text;
streamText
method
Generate and stream text in real-time
saveStreamDeltas
boolean | StreamingOptions
Whether to save streaming chunks to the database
Returns: StreamTextResult with textStream, text, finishReason

Object Generation

Generate structured objects using schemas:
import { z } from "zod";

const result = await agent.generateObject(ctx,
  { threadId },
  {
    schema: z.object({
      name: z.string(),
      age: z.number(),
      email: z.string().email(),
    }),
    prompt: "Extract: John is 30 years old, email john@example.com",
  }
);

console.log(result.object);
// { name: "John", age: 30, email: "john@example.com" }
generateObject
method
Generate structured objects
schema
ZodSchema | JSONSchema
required
Schema for the output object
prompt
string
required
The user prompt
Returns: GenerateObjectResult with typed object

Tools

Create tools for agents to call:
import { createTool } from "@packages/agent";
import { z } from "zod";

const weatherTool = createTool({
  args: z.object({
    city: z.string(),
  }),
  description: "Get the weather for a city",
  handler: async (ctx, { city }) => {
    // Fetch weather data
    return `The weather in ${city} is sunny.`;
  },
});

const agent = new Agent(components.agent, {
  name: "weather-agent",
  languageModel: openai.chat("gpt-4o"),
  tools: { weather: weatherTool },
});
createTool
function
Create a tool for agent function calling
args
ZodSchema
required
Zod schema for tool arguments
description
string
required
Description of what the tool does
handler
function
required
Handler function: (ctx: ToolCtx, args) => Promise<string | object>

Message Management

Save Messages

const { messageId } = await agent.saveMessage(ctx, {
  threadId,
  userId,
  message: {
    role: "user",
    content: "Hello!",
  },
});

List Messages

const messages = await agent.listMessages(ctx, {
  threadId,
  paginationOpts: { numItems: 50 },
  excludeToolMessages: true,
});

Delete Messages

// Delete specific messages
await agent.deleteMessages(ctx, {
  messageIds: ["msg_123", "msg_456"],
});

// Delete by range
await agent.deleteMessageRange(ctx, {
  threadId,
  startOrder: 1,
  endOrder: 5,
});

Context & RAG

Fetch relevant context from previous messages:
const contextMessages = await agent.fetchContextMessages(ctx, {
  userId,
  threadId,
  searchText: "How do I deploy?",
  contextOptions: {
    maxMessages: 10,
    vectorSearch: true,
  },
});

React Integration

Use with React hooks:
import { useThreadMessages } from "@packages/agent/react";
import { useQuery } from "convex/react";

function ChatInterface({ threadId }) {
  const messages = useThreadMessages(threadId);
  
  return (
    <div>
      {messages.map(msg => (
        <div key={msg._id}>
          <strong>{msg.role}:</strong> {msg.content}
        </div>
      ))}
    </div>
  );
}

Exports

.
module
Main agent exports - Agent, createTool, message utilities
./validators
module
Validation schemas for messages and threads
./react
module
React hooks for agent integration
./test
module
Testing utilities
./http
module
HTTP streaming utilities

Testing

import { mockModel } from "@packages/agent";

const testAgent = new Agent(components.agent, {
  name: "test-agent",
  languageModel: mockModel({
    responses: ["Hello!", "How can I help?"],
  }),
});