Convex agent skill
Skill PolarCoding85/convex-agent-skillz/.claude/skills/convex-agent-skill
Build AI agents with persistent threads, tool calling, and streaming on Convex. Use when implementing chat interfaces, AI assistants, multi-agent workflows, RAG systems, or any LLM-powered features with message history.From its SKILL.md
npx -y skills add PolarCoding85/convex-agent-skillz --skill convex-agent-skillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 17 stars17 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 2 commands, including `npm install @convex-dev/agent` and 1 more.
SKILL.md
6.8 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it
Convex Agent Component
Build AI agents with persistent message history, tool calling, real-time streaming, and durable workflows.
Installation
npm install @convex-dev/agent
// convex/convex.config.ts
import { defineApp } from 'convex/server';
import agent from '@convex-dev/agent/convex.config';
const app = defineApp();
app.use(agent);
export default app;
Run npx convex dev to generate component code before defining agents.
Core Concepts
Agent Definition
// convex/agents.ts
import { Agent } from '@convex-dev/agent';
import { openai } from '@ai-sdk/openai';
import { components } from './_generated/api';
const supportAgent = new Agent(components.agent, {
name: 'Support Agent',
languageModel: openai.chat('gpt-4o-mini'),
textEmbeddingModel: openai.embedding('text-embedding-3-small'), // For vector search
instructions: 'You are a helpful support assistant.',
tools: { lookupAccount, createTicket },
stopWhen: stepCountIs(10) // Or use maxSteps: 10
});
Basic Usage (Two Approaches)
Approach 1: Direct generation (simpler)
import { createThread } from '@convex-dev/agent';
export const chat = action({
args: { prompt: v.string() },
handler: async (ctx, { prompt }) => {
const threadId = await createThread(ctx, components.agent);
const result = await agent.generateText(ctx, { threadId }, { prompt });
return result.text;
}
});
Approach 2: Thread object (more features)
export const chat = action({
args: { prompt: v.string() },
handler: async (ctx, { prompt }) => {
const { threadId, thread } = await agent.createThread(ctx);
const result = await thread.generateText({ prompt });
return { threadId, text: result.text };
}
});
Continue Existing Thread
export const continueChat = action({
args: { threadId: v.string(), prompt: v.string() },
handler: async (ctx, { threadId, prompt }) => {
// Message history included automatically
const result = await agent.generateText(ctx, { threadId }, { prompt });
return result.text;
}
});
Asynchronous Pattern (Recommended)
Best practice: save message in mutation, generate response asynchronously.
import { saveMessage } from '@convex-dev/agent';
// Step 1: Mutation saves message and schedules generation
export const sendMessage = mutation({
args: { threadId: v.string(), prompt: v.string() },
handler: async (ctx, { threadId, prompt }) => {
const { messageId } = await saveMessage(ctx, components.agent, {
threadId,
prompt
});
await ctx.scheduler.runAfter(0, internal.chat.generateResponse, {
threadId,
promptMessageId: messageId
});
return messageId;
}
});
// Step 2: Action generates response
export const generateResponse = internalAction({
args: { threadId: v.string(), promptMessageId: v.string() },
handler: async (ctx, { threadId, promptMessageId }) => {
await agent.generateText(ctx, { threadId }, { promptMessageId });
}
});
// Shorthand for Step 2:
export const generateResponse = agent.asTextAction();
Generation Methods
// Text generation
const result = await agent.generateText(ctx, { threadId }, { prompt });
// Structured output
const result = await agent.generateObject(
ctx,
{ threadId },
{
prompt: 'Extract user info',
schema: z.object({ name: z.string(), email: z.string() })
}
);
// Stream text (see STREAMING.md)
const result = await agent.streamText(ctx, { threadId }, { prompt });
// Multiple messages
const result = await agent.generateText(
ctx,
{ threadId },
{
messages: [
{ role: 'user', content: 'Context message' },
{ role: 'user', content: 'Actual question' }
]
}
);
Querying Messages
import { listUIMessages, paginationOptsValidator } from '@convex-dev/agent';
export const listMessages = query({
args: { threadId: v.string(), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
return await listUIMessages(ctx, components.agent, args);
}
});
React Hook:
import { useUIMessages } from '@convex-dev/agent/react';
const { results, status, loadMore } = useUIMessages(
api.chat.listMessages,
{ threadId },
{ initialNumItems: 20 }
);
Agent Configuration Options
const agent = new Agent(components.agent, {
name: 'Agent Name',
languageModel: openai.chat('gpt-4o-mini'),
textEmbeddingModel: openai.embedding('text-embedding-3-small'),
instructions: 'System prompt...',
tools: {
/* tools */
},
stopWhen: stepCountIs(10), // Or maxSteps: 10
// Context options (see CONTEXT.md)
contextOptions: {
recentMessages: 100,
excludeToolMessages: true,
searchOptions: { limit: 10, textSearch: false, vectorSearch: false }
},
// Storage options
storageOptions: { saveMessages: 'promptAndOutput' }, // 'all' | 'none'
// Handlers
usageHandler: async (ctx, { usage, model, provider, agentName }) => {},
contextHandler: async (ctx, { allMessages }) => allMessages,
rawRequestResponseHandler: async (ctx, { request, response }) => {},
// Call settings
callSettings: { maxRetries: 3, temperature: 1.0 }
});
Key References
- Streaming - Delta streaming, HTTP streaming, text smoothing
- Tools - Defining and using tools with Convex context
- Context - Customizing LLM context and RAG
- Threads - Thread management and deletion
- Messages - Message storage, ordering, UIMessage type
- Workflows - Durable multi-step workflows
- Human Agents - Mixing human and AI responses
- Files - Images and files in messages
- RAG - Retrieval-augmented generation patterns
- Rate Limiting - Controlling request rates
- Usage Tracking - Token usage and billing
- Debugging - Troubleshooting and playground
Best Practices
- Define agents at module level - Reuse across functions
- Use
userIdon threads - Enables cross-thread search and per-user data - Set appropriate
stopWhen/maxSteps- Prevents runaway tool loops - Use
promptMessageIdfor async - Enables safe retries without duplicates - Save messages in mutations - Use optimistic updates, schedule actions
- Use
textEmbeddingModelfor RAG - Required for vector search - Handle streaming via deltas - Better UX than HTTP streaming alone
What ships with it: 13 files
70.2 KB alongside SKILL.md
references/
- CONTEXT.md5.1 KB
- DEBUGGING.md5.2 KB
- FILES.md5.6 KB
- HUMAN-AGENTS.md6.2 KB
- MESSAGES.md5.6 KB
- PERSISTENT-TEXT-STREAMING.md5.5 KB
- RAG.mD5.8 KB
- RATE-LIMITING.md5.6 KB
- STREAMING.md5.2 KB
- THREADS.md3.6 KB
- TOOLS.md4.8 KB
- USAGE-TRACKING.md6.4 KB
- WORKFLOWS.md5.5 KB