Skip to main content

Threads

Threads are a way to group messages together in a linear history. All messages saved in the Agent component are associated with a thread. When a message is generated based on a prompt, it saves the user message and generated agent message(s) automatically.

Threads can be associated with a user, and messages can each individually be associated with a user. By default, messages are associated with the thread's user.

Creating a thread

You can create a thread in a mutation or action. If you create it in an action, it will also return a thread (see below) and you can start calling LLMs and generating messages. If you specify a userId, the thread will be associated with that user and messages will be saved to the user's history.

import { createThread } from "@convex-dev/agent";

const threadId = await createThread(ctx, components.agent);

You may also pass in metadata to set on the thread:

const userId = await getAuthUserId(ctx);
const threadId = await createThread(ctx, components.agent, {
userId,
title: "My thread",
summary: "This is a summary of the thread",
});

Metadata may be provided as context to the agent automatically in the future, but for now it's a convenience that helps organize threads in the Playground.

Generating a message in a thread

You can generate a message in a thread via the agent functions: agent.generateText, agent.generateObject, agent.streamText, and agent.streamObject. Any agent can generate a message in a thread created by any other agent.

const agent = new Agent(components.agent, { languageModel, instructions });

export const generateReplyToPrompt = action({
args: { prompt: v.string(), threadId: v.string() },
handler: async (ctx, { prompt, threadId }) => {
// await authorizeThreadAccess(ctx, threadId);
const result = await agent.generateText(ctx, { threadId }, { prompt });
return result.text;
},
});

See Messages for more details on creating and saving messages.

Continuing a thread using the thread object from agent.continueThread

You can also continue a thread by creating an agent-specific thread object, either when calling agent.createThread or agent.continueThread from within an action. This allows calling methods without specifying those parameters each time.

const { thread } = await agent.continueThread(ctx, { threadId });
const result = await thread.generateText({ prompt });

The thread from continueThread or createThread (available in actions only) is a Thread object, which has convenience methods that are thread-specific:

  • thread.getMetadata() to get the userId, title, summary etc.
  • thread.updateMetadata({ patch: { title, summary, userId} }) to update the metadata
  • thread.generateText({ prompt, ... }) - equivalent to agent.generateText(ctx, { threadId }, { prompt, ... })
  • thread.streamText({ prompt, ... }) - equivalent to agent.streamText(ctx, { threadId }, { prompt, ... })
  • thread.generateObject({ prompt, ... }) - equivalent to agent.generateObject(ctx, { threadId }, { prompt, ... })
  • thread.streamObject({ prompt, ... }) - equivalent to agent.streamObject(ctx, { threadId }, { prompt, ... })

See Messages docs for more details on generating messages.

Deleting threads

You can delete threads by their threadId.

Asynchronously (from a mutation or action):

await agent.deleteThreadAsync(ctx, { threadId });

Synchronously in batches (from an action):

await agent.deleteThreadSync(ctx, { threadId });

You can also delete all threads by a user by their userId.

await agent.deleteThreadsByUserId(ctx, { userId });

Getting all threads owned by a user

const threads = await ctx.runQuery(
components.agent.threads.listThreadsByUserId,
{ userId, paginationOpts: args.paginationOpts },
);

Deleting all threads and messages associated with a user

Asynchronously (from a mutation or action):

await ctx.runMutation(components.agent.users.deleteAllForUserIdAsync, {
userId,
});

Synchronously (from an action):

await ctx.runMutation(components.agent.users.deleteAllForUserId, { userId });

Getting messages in a thread

See messages.mdx for more details.

import { listMessages } from "@convex-dev/agent";

const messages = await listMessages(ctx, components.agent, {
threadId,
excludeToolMessages: true,
paginationOpts: { cursor: null, numItems: 10 }, // null means start from the beginning
});