@mastra/core
Version:
348 lines (260 loc) • 11 kB
Markdown
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
# Message history
Message history is the most basic and important form of memory. It gives the LLM a view of recent messages in the context window, enabling your agent to reference earlier exchanges and respond coherently.
You can also retrieve message history to display past conversations in your UI.
> **Info:** Each message belongs to a thread (the conversation) and a resource (the user or entity it's associated with). See [Threads and resources](#threads-and-resources) for more detail.
> **Warning:** When you use memory with a client application, send **only the new message** from the client instead of the full conversation history.
>
> Sending the full history is redundant because Mastra loads messages from storage, and it can cause message ordering bugs when client-side timestamps conflict with stored timestamps.
>
> For an AI SDK example, see [Using Mastra Memory](https://mastra.ai/guides/build-your-ui/ai-sdk-ui).
## Threads and resources
Mastra organizes conversations using two identifiers:
- **Thread**: A conversation session containing a sequence of messages.
- **Resource**: The entity that owns the thread, such as a user, organization, project, or another domain entity in your application.
Studio automatically generates a thread and resource ID for you. When calling `stream()` or `generate()` yourself, provide these identifiers explicitly.
## Getting started
Install the Mastra memory module along with a [storage adapter](https://mastra.ai/docs/storage/overview) for your database. The examples below use `@mastra/libsql`, which stores data locally in a `mastra.db` file.
**npm**:
```bash
npm install @mastra/memory@latest @mastra/libsql@latest
```
**pnpm**:
```bash
pnpm add @mastra/memory@latest @mastra/libsql@latest
```
**Yarn**:
```bash
yarn add @mastra/memory@latest @mastra/libsql@latest
```
**Bun**:
```bash
bun add @mastra/memory@latest @mastra/libsql@latest
```
Message history requires a storage adapter to persist conversations. Configure storage on your Mastra instance if you haven't already:
```typescript
import { Mastra } from '@mastra/core'
import { LibSQLStore } from '@mastra/libsql'
export const mastra = new Mastra({
storage: new LibSQLStore({
id: 'mastra-storage',
url: 'file:./mastra.db',
}),
})
```
Instantiate a [`Memory`](https://mastra.ai/reference/memory/memory-class) instance in your agent:
```typescript
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
export const agent = new Agent({
id: 'test-agent',
memory: new Memory({
options: {
lastMessages: 10,
},
}),
})
```
When you call the agent, messages are automatically saved to the database. You can specify a `threadId`, `resourceId`, and optional `metadata`:
**.generate()**:
```typescript
await agent.generate('Hello', {
memory: {
thread: {
id: 'thread-123',
title: 'Support conversation',
metadata: { category: 'billing' },
},
resource: 'user-456',
},
})
```
**.stream()**:
```typescript
await agent.stream('Hello', {
memory: {
thread: {
id: 'thread-123',
title: 'Support conversation',
metadata: { category: 'billing' },
},
resource: 'user-456',
},
})
```
> **Info:** Threads and messages are created automatically when you call `agent.generate()` or `agent.stream()`, but you can also create them manually with [`createThread()`](https://mastra.ai/reference/memory/createThread) and [`saveMessages()`](https://mastra.ai/reference/memory/memory-class).
You can use this history in two ways:
- **Automatic inclusion**: Mastra automatically fetches and includes recent messages in the context window. By default, it includes the last 10 messages, keeping agents grounded in the conversation. You can adjust this number with `lastMessages`, but in most cases you don't need to think about it.
- [**Manual querying**](#querying): For more control, use the `recall()` function to query threads and messages directly. This lets you choose exactly which memories are included in the context window, or fetch messages to render conversation history in your UI.
> **Tip:** When memory is enabled, [Studio](https://mastra.ai/docs/studio/overview) uses message history to display past conversations in the chat sidebar.
## Thread title generation
Mastra can automatically generate descriptive thread titles from the conversation transcript when `generateTitle` is enabled. Use this option when you build a chat interface that renders conversation titles in a thread list or sidebar.
```typescript
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support agent',
instructions: 'Answer customer support questions.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
generateTitle: true,
},
}),
})
```
Title generation runs asynchronously after the agent responds and doesn't affect response time.
To optimize cost or behavior, provide a smaller [`model`](https://mastra.ai/models) and custom `instructions`:
```typescript
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support agent',
instructions: 'Answer customer support questions.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
generateTitle: {
model: 'openai/gpt-5-mini',
instructions: 'Generate a one-word title.',
},
},
}),
})
```
## Accessing memory
To access memory functions for querying, cloning, or deleting threads and messages, call `getMemory()` on an agent:
```typescript
const agent = mastra.getAgentById('test-agent')
const memory = await agent.getMemory()
```
The `Memory` instance gives you access to functions for listing threads and recalling messages, plus cloning conversations, and more.
## Querying
Use these methods to fetch threads and messages for displaying conversation history in your UI or for custom memory retrieval logic.
> **Warning:** The memory system doesn't enforce access control. Before running any query, verify in your application logic that the current user is authorized to access the `resourceId` being queried.
### Threads
Use [`listThreads()`](https://mastra.ai/reference/memory/listThreads) to retrieve threads for a resource:
```typescript
const result = await memory.listThreads({
filter: { resourceId: 'user-123' },
perPage: false,
})
```
Paginate through threads:
```typescript
const result = await memory.listThreads({
filter: { resourceId: 'user-123' },
page: 0,
perPage: 10,
})
console.log(result.threads) // thread objects
console.log(result.hasMore) // more pages available?
```
You can also filter by metadata and control sort order:
```typescript
const result = await memory.listThreads({
filter: {
resourceId: 'user-123',
metadata: { status: 'active' },
},
orderBy: { field: 'createdAt', direction: 'DESC' },
})
```
To fetch a single thread by ID, use [`getThreadById()`](https://mastra.ai/reference/memory/getThreadById):
```typescript
const thread = await memory.getThreadById({ threadId: 'thread-123' })
```
### Messages
Once you have a thread, use [`recall()`](https://mastra.ai/reference/memory/recall) to retrieve its messages. It supports pagination, date filtering, and [semantic search](https://mastra.ai/docs/memory/semantic-recall).
Basic recall returns all messages from a thread:
```typescript
const { messages } = await memory.recall({
threadId: 'thread-123',
perPage: false,
})
```
Paginate through messages:
```typescript
const { messages } = await memory.recall({
threadId: 'thread-123',
page: 0,
perPage: 50,
})
```
Filter by date range:
```typescript
const { messages } = await memory.recall({
threadId: 'thread-123',
filter: {
dateRange: {
start: new Date('2025-01-01'),
end: new Date('2025-06-01'),
},
},
})
```
Filter by shallow message metadata:
```typescript
const { messages } = await memory.recall({
threadId: 'thread-123',
filter: {
metadata: {
category: 'billing',
escalated: true,
priority: 2,
archivedAt: null,
},
},
})
```
Metadata filters match shallow scalar values only: `string`, finite `number`, `boolean`, and `null`.
All specified metadata keys use AND semantics. A `null` filter matches only an explicit `null` value. A missing metadata key doesn't match.
Metadata keys must start with a letter or underscore and contain only alphanumeric characters. They must be 128 characters or fewer and can't use reserved prototype keys such as `__proto__`, `constructor`, or `prototype`.
Performance depends on the storage backend. Some backends can push parts of the filter into the database, while others scan candidate messages after thread, resource, and date constraints are applied but before pagination.
Fetch a single message by ID:
```typescript
const { messages } = await memory.recall({
threadId: 'thread-123',
include: [{ id: 'msg-123' }],
})
```
Fetch multiple messages by ID with surrounding context:
```typescript
const { messages } = await memory.recall({
threadId: 'thread-123',
include: [
{ id: 'msg-123' },
{
id: 'msg-456',
withPreviousMessages: 3,
withNextMessages: 1,
},
],
})
```
Search by meaning (see [Semantic recall](https://mastra.ai/docs/memory/semantic-recall) for setup):
```typescript
const { messages } = await memory.recall({
threadId: 'thread-123',
vectorSearchString: 'project deadline discussion',
threadConfig: {
semanticRecall: true,
},
})
```
### UI format
Message queries return `MastraDBMessage[]` format. To display messages in a frontend, you may need to convert them to a format your UI library expects. For example, [`toAISdkV5Messages`](https://mastra.ai/reference/ai-sdk/to-ai-sdk-v5-messages) converts messages to AI SDK UI format.
## Thread cloning
Thread cloning creates a copy of an existing thread with its messages. This is useful for branching conversations or creating checkpoints before a potentially destructive operation, or alternatively testing variations of a conversation.
```typescript
const { thread, clonedMessages } = await memory.cloneThread({
sourceThreadId: 'thread-123',
title: 'Branched conversation',
})
```
You can filter which messages get cloned (by count or date range), specify custom thread IDs, and use utility methods to inspect clone relationships.
See [`cloneThread()`](https://mastra.ai/reference/memory/cloneThread) and [clone utilities](https://mastra.ai/reference/memory/clone-utilities) for the full API.
## Deleting messages
To remove messages from a thread, use [`deleteMessages()`](https://mastra.ai/reference/memory/deleteMessages). You can delete by message ID or clear all messages from a thread.