К основному содержанию
скилл CX Codex

convex-agents — скилл для Claude Code: что делает и как установить

Скилл учит ИИ строить агентов на компоненте @convex-dev/agent. Пригодится для чатов с историей тредов, RAG и вызова мутаций Convex как инструментов.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add waynesutton/builder-skills --skill convex-agents -a claude-code
Открыть на GitHub

Что делает convex-agents

Скилл задаёт архитектуру агентов для бэкенда Convex. Он помогает генерировать код с тредами, реактивным списком сообщений через хук useUIMessages и инструментами createTool, которые вызывают мутации и запросы через контекст базы.

Главное архитектурное правило: генерация текста модели обязана запускаться внутри Convex action, а не в мутации. Мутация лишь сохраняет вопрос через saveMessage и ставит фоновую задачу через ctx.scheduler.runAfter. Если вызвать generateText прямо в мутации, код сразу сломается, так как мутации в Convex должны быть детерминированными и не могут делать сетевые вызовы.

Для работы требуются библиотеки @convex-dev/agent, ai, @ai-sdk/openai и zod, а также ключ OPENAI_API_KEY. Перед объявлением агентов нужно один раз запустить npx convex dev, чтобы сгенерировать components.agent.

Какие задачи решает

  • подключить чат-ассистента с сохранением истории сообщений в Convex
  • настроить вызов мутаций и запросов базы как инструментов модели через createTool
  • реализовать реактивное отображение сообщений в интерфейсе через useUIMessages
  • разбить запуск LLM на сохранение промпта в мутации и генерацию ответа в internalAction

Примеры запросов агенту

  • Добавь в проект агента поддержки на базе @convex-dev/agent с моделью gpt-4o-mini
  • Создай инструмент searchOrders с валидацией через Zod, который ищет заказы пользователя
  • Настрой мутацию sendMessage и фоновый internalAction для генерации ответа модели

Как установить convex-agents

1Через Skills CLI (Vercel)

npx skills add waynesutton/builder-skills --skill convex-agents -a claude-code

2Вручную: положить файлы

~/.claude/skills/convex-agents/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/convex-agents/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора14

convex-cron-jobs Настраивает периодические задачи в convex/crons.ts и отложенный запуск через ctx.scheduler. Помогает разбить мутации на пачки и отладить фоновые очереди. CX Codex +1 2 800установок convex-security-check Проверяет Convex-бэкенд перед слиянием изменений: публичные функции, авторизацию, владение данными, валидацию и секреты. CX Codex +1 2 700установок convex-http-actions Добавляет HTTP-эндпоинты в convex/http.ts: приём вебхуков с проверкой подписи, REST-маршруты, CORS, стриминг и загрузка файлов. CX Codex +1 2 700установок convex-migrations Проводит изменение схемы Convex через шесть шагов: сделать поле необязательным, залить данные батчами, переключить валидатор, подчистить. Пригодится, когда npx convex dev падает на существующих документах. CX Codex +1 2 600установок convex-file-storage Настраивает хранение файлов в Convex: загрузку через временные URL, сохранение blob в actions и раздачу через getUrl. Пригодится при работе с документами и пользовательскими картинками. CX Codex +1 2 600установок convex-security-audit Скилл проводит полный разбор безопасности приложения на Convex и выдаёт письменный отчёт по найденным проблемам. Пригодится перед запуском или после инцидента. CX Codex +1 1 500установок avoid-feature-creep Удерживает правки агента строго в границах задачи. Выносит попутный рефакторинг и лишние фичи в отдельный список предложений вместо diff. CX Codex +1 1 300установок convex-component-authoring Собирает переиспользуемый компонент Convex: своя схема, функции и клиентская обёртка. Пригодится, когда фичу выносят в пакет. CX Codex +1 1 200установок

Похожие

convex convex Скилл-маршрутизатор для работы с бэкендом Convex: отправляет задачу нужному навыку из набора convex-* и подтягивает свежие инструкции из серверного каталога. CX Codex +1 108 000установок convex-agent convex Ставит в приложение на Convex бэкенд для ИИ-агента: долгие треды, история сообщений, вызовы инструментов и поиск по векторам. CX Codex +1 35 900установок langchain4j-spring-boot-integration giuseppe-trisciuoglio Скилл настраивает интеграцию LangChain4j в Spring Boot: генерирует бины моделей, RAG-цепочки со Spring Data и декларативные сервисы с аннотацией @AiService. CX Codex +1 3 700установок cargo-ai getcargo Скилл для работы с ИИ-агентами в Cargo прямо из чата: создать агента, задать модель и промпт, подключить базу знаний и MCP-серверы, задеплоить релиз. CX Codex +1 9 900установок mastra-hono agent-skills Скилл для сборки ИИ-агентов, инструментов и воркфлоу на Mastra v1 Beta с API-серверами на Hono. Пригодится, когда пишете агентную логику на TypeScript. CX Codex +1 373установок developing-genkit-js официальный google Скилл помогает создавать и чинить AI-приложения на Genkit для Node.js и TypeScript. Пригодится для flows, агентов, tools и ошибок API. CX Codex 3 600установок

Рядом в теме «Настройка агента: память, контекст, субагенты»

Все скиллы по теме «Настройка агента: память, контекст, субагенты» →

Вопросы о convex-agents

Как установить convex-agents в Claude Code?

Выполните команду npx skills add waynesutton/builder-skills --skill convex-agents -a claude-code.

Что делает скилл convex-agents?

Он предоставляет шаблоны и правила для разработки ИИ-агентов на базе @convex-dev/agent с поддержкой тредов, вызова инструментов и стриминга.

Почему нельзя вызывать LLM напрямую внутри мутации Convex?

Мутации обязаны оставаться детерминированными и не могут выполнять сетевые запросы. Скилл настраивает схему, где мутация сохраняет промпт, а за генерацию отвечает internalAction.

Исходный текст

SKILL.md · Apache-2.0
---
name: convex-agents
description: Builds AI agents on the Convex agent component: threads, messages, tools that call queries and mutations, streaming, RAG with vector search, and workflows for multi step jobs. Use when adding a chat assistant, tool calling agent, or retrieval feature to a Convex app.
---

# Convex agents

Produces a chat or tool calling agent backed by `@convex-dev/agent`, with thread history stored in Convex and a reactive message list for the UI. The one rule: every LLM call runs inside an action. Mutations save the prompt and schedule the action; they never call a model.

## When to reach for this

- Adding a chat assistant with persistent conversation history
- Letting an LLM call your queries and mutations as tools
- Streaming a model reply to one or more clients
- Answering questions over your own documents (RAG)
- Chaining several LLM steps into a durable job that survives restarts

## Install and register

```bash
npm install @convex-dev/agent ai @ai-sdk/openai zod
npx convex env set OPENAI_API_KEY sk-...
```

```typescript
// 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` once so `components.agent` is generated before defining an agent.

## Define an agent

```typescript
// convex/agent.ts
import { Agent, stepCountIs } from "@convex-dev/agent";
import { openai } from "@ai-sdk/openai";
import { components } from "./_generated/api";

export const supportAgent = new Agent(components.agent, {
  name: "Support Agent",
  languageModel: openai.chat("gpt-4o-mini"),
  instructions: "You are a support assistant. Answer briefly and cite docs when possible.",
  // Lets the model call tools and then respond, up to 5 steps
  stopWhen: stepCountIs(5),
});
```

`name` tags each saved message with the agent that wrote it. Everything except `name` can be overridden per call.

## Create a thread and generate a reply

Save the user prompt in a mutation, then schedule an internal action that generates the reply. Clients subscribed to the thread see the new message without the action returning anything.

```typescript
// convex/chat.ts
import { v } from "convex/values";
import { mutation, internalAction, QueryCtx, MutationCtx } from "./_generated/server";
import { components, internal } from "./_generated/api";
import { saveMessage } from "@convex-dev/agent";
import { supportAgent } from "./agent";

// Throws unless the signed in user owns the thread
async function authorizeThreadAccess(ctx: QueryCtx | MutationCtx, threadId: string) {
  const identity = await ctx.auth.getUserIdentity();
  if (!identity) throw new Error("Not authenticated");
  const thread = await ctx.runQuery(components.agent.threads.getThread, { threadId });
  if (!thread || thread.userId !== identity.subject) throw new Error("Unauthorized");
}

export const startThread = mutation({
  args: {},
  returns: v.string(),
  handler: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new Error("Not authenticated");
    const { threadId } = await supportAgent.createThread(ctx, { userId: identity.subject });
    return threadId;
  },
});

export const sendMessage = mutation({
  args: { threadId: v.string(), prompt: v.string() },
  returns: v.null(),
  handler: async (ctx, args) => {
    await authorizeThreadAccess(ctx, args.threadId);
    const { messageId } = await saveMessage(ctx, components.agent, {
      threadId: args.threadId,
      prompt: args.prompt,
    });
    await ctx.scheduler.runAfter(0, internal.chat.generateReply, {
      threadId: args.threadId,
      promptMessageId: messageId,
    });
    return null;
  },
});

export const generateReply = internalAction({
  args: { threadId: v.string(), promptMessageId: v.string() },
  returns: v.null(),
  handler: async (ctx, args) => {
    // promptMessageId makes retries safe: the same prompt is reused, never duplicated
    await supportAgent.generateText(
      ctx,
      { threadId: args.threadId },
      { promptMessageId: args.promptMessageId },
    );
    return null;
  },
});
```

Thread ids are strings, not `v.id(...)`, since the table lives inside the component.

## List messages for the UI

```typescript
// convex/chat.ts (continued)
import { paginationOptsValidator } from "convex/server";
import { listUIMessages } from "@convex-dev/agent";
import { query } from "./_generated/server";

export const listMessages = query({
  args: { threadId: v.string(), paginationOpts: paginationOptsValidator },
  handler: async (ctx, args) => {
    await authorizeThreadAccess(ctx, args.threadId);
    return await listUIMessages(ctx, components.agent, args);
  },
});
```

```tsx
// src/Chat.tsx
import { useUIMessages } from "@convex-dev/agent/react";
import { api } from "../convex/_generated/api";

function Chat({ threadId }: { threadId: string }) {
  const { results, status, loadMore } = useUIMessages(
    api.chat.listMessages,
    { threadId },
    { initialNumItems: 20 },
  );
  return (
    <div>
      {results.map((m) => (
        <div key={m.key} data-role={m.role}>{m.text}</div>
      ))}
      {status === "CanLoadMore" && <button onClick={() => loadMore(20)}>Older</button>}
    </div>
  );
}
```

`listUIMessages` merges tool calls and the assistant text that follows them into one `UIMessage`, which keeps rendering simple.

## One tool

Tools are defined with `createTool` and get a `ctx` that includes `runQuery`, `runMutation`, `userId`, and `threadId`. Annotate the handler return type to avoid circular type errors.

```typescript
// convex/tools.ts
import { createTool } from "@convex-dev/agent";
import { z } from "zod";
import { api } from "./_generated/api";

export const searchOrders = createTool({
  description: "Find the current user's orders that match a search term",
  args: z.object({
    term: z.string().describe("Product name or order number to look for"),
  }),
  handler: async (ctx, args): Promise<Array<{ id: string; status: string }>> => {
    return await ctx.runQuery(api.orders.search, { term: args.term });
  },
});
```

Pass it to the agent with `tools: { searchOrders }` in the constructor or at the call site. For tool error handling, runtime tools with closures, and delta streaming to the client, open [references/tools-and-streaming.md](references/tools-and-streaming.md).

## Retrieval and multi step jobs

For embedding documents, searching them with `@convex-dev/rag` or a hand rolled vector index, injecting results into the prompt, and running several LLM steps as a durable `@convex-dev/workflow` job, open [references/rag-and-workflows.md](references/rag-and-workflows.md).

## Common mistakes

| Mistake | Why it breaks | Do instead |
| --- | --- | --- |
| Calling `generateText` in a mutation | Mutations cannot make network calls and must be deterministic | Save the prompt with `saveMessage`, schedule an `internalAction` |
| `v.id("threads")` for thread ids | The threads table lives in the component, so ids are strings outside it | Use `v.string()` |
| Skipping `npx convex dev` after `app.use(agent)` | `components.agent` is not generated, so types fail | Run dev once before writing agent code |
| Returning the reply text from the action to the client | Loses the reply if the client disconnects, no reactivity | Let clients read `listUIMessages`; the saved message shows up on its own |
| Tools without `.describe()` on args | The model guesses what each field means and calls tools badly | Describe every zod field |
| Tool handler with no return type annotation | TypeScript circularity errors from `ctx.runQuery` | Add `: Promise<...>` to the handler |
| Exposing the message query with no auth check | Any client can read any thread | Call an `authorizeThreadAccess` helper first |
| `stopWhen` left at the default with tools defined | The model calls a tool and stops without a text reply | Set `stopWhen: stepCountIs(n)` with `n > 1` |

## Checklist

- [ ] `app.use(agent)` in `convex.config.ts` and `npx convex dev` has run
- [ ] Provider key stored with `npx convex env set`, never in client code
- [ ] `Agent` has a `name`, `languageModel`, and `instructions`
- [ ] Prompts saved in a mutation, replies generated in an `internalAction` with `promptMessageId`
- [ ] Thread and message ids typed as `v.string()`
- [ ] Message list query checks thread ownership before calling `listUIMessages`
- [ ] Every tool arg has a zod `.describe()` and the handler has a return type
- [ ] `stopWhen: stepCountIs(n)` set when tools are in play
- [ ] Client uses `useUIMessages` rather than reading action return values

## Docs

- https://docs.convex.dev/llms.txt
- https://docs.convex.dev/agents
- https://docs.convex.dev/agents/agent-usage
- https://docs.convex.dev/agents/tools
- https://www.convex.dev/components/agent

© waynesutton · Apache-2.0 · waynesutton/builder-skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой