@mastra/libsql 0.0.0-fix-thread-subscription-multi-instance-redis-streams-20260720232722 → 0.0.0-fix-thread-subscription-multi-instance-redis-streams-20260730204150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +249 -9
- package/dist/docs/SKILL.md +4 -3
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-agent-builder-deploying.md +2 -2
- package/dist/docs/references/docs-agent-builder-overview.md +3 -1
- package/dist/docs/references/docs-agents-agent-approval.md +85 -11
- package/dist/docs/references/docs-agents-networks.md +2 -2
- package/dist/docs/references/docs-deployment-workers.md +137 -0
- package/dist/docs/references/docs-memory-memory-processors.md +10 -10
- package/dist/docs/references/docs-memory-message-history.md +29 -5
- package/dist/docs/references/docs-memory-multi-user-threads.md +6 -6
- package/dist/docs/references/docs-memory-overview.md +10 -10
- package/dist/docs/references/docs-memory-semantic-recall.md +3 -3
- package/dist/docs/references/docs-memory-working-memory.md +8 -8
- package/dist/docs/references/docs-rag-retrieval.md +18 -18
- package/dist/docs/references/docs-storage-overview.md +2 -2
- package/dist/docs/references/docs-workflows-snapshots.md +3 -3
- package/dist/docs/references/reference-core-mastra-class.md +48 -1
- package/dist/docs/references/reference-file-based-agents-storage.md +1 -1
- package/dist/docs/references/reference-memory-memory-class.md +5 -5
- package/dist/docs/references/reference-storage-dynamodb.md +7 -7
- package/dist/docs/references/reference-storage-retention.md +33 -33
- package/dist/docs/references/reference-vectors-libsql.md +2 -2
- package/dist/index.cjs +12742 -13175
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +12708 -13141
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/datasets/index.d.ts.map +1 -1
- package/dist/storage/domains/experiments/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/factory-storage.d.ts +28 -0
- package/dist/storage/factory-storage.d.ts.map +1 -0
- package/dist/storage/index.d.ts +2 -9
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts +1 -7
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +13 -12
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
3
|
+
# Workers
|
|
4
|
+
|
|
5
|
+
> **Beta:** This feature is in beta. The API is stable enough for production use, but some details may change. See [known limitations](#known-limitations) for current gaps.
|
|
6
|
+
|
|
7
|
+
Workers handle background processing outside the request-response cycle. Workflow step execution, cron-based scheduling, and long-running tool calls all run in workers, keeping the API responsive.
|
|
8
|
+
|
|
9
|
+
By default, workers run in the same process as the API. For production workloads, you can split them into separate processes or containers and scale each one independently.
|
|
10
|
+
|
|
11
|
+
## When to use workers
|
|
12
|
+
|
|
13
|
+
Workers matter when any of these apply:
|
|
14
|
+
|
|
15
|
+
- Workflow steps take more than a few seconds and shouldn't block API responses
|
|
16
|
+
- You need event durability so in-flight work survives process restarts
|
|
17
|
+
- Different parts of the system need to scale independently (e.g., more orchestration capacity without more API instances)
|
|
18
|
+
- Background tool calls should run on dedicated compute
|
|
19
|
+
|
|
20
|
+
If your application handles light traffic and workflows complete quickly, the default in-process setup works fine. Skip the worker infrastructure until you need it.
|
|
21
|
+
|
|
22
|
+
## Worker types
|
|
23
|
+
|
|
24
|
+
Mastra has three built-in worker types. Each handles a specific kind of background processing.
|
|
25
|
+
|
|
26
|
+
### Orchestration worker
|
|
27
|
+
|
|
28
|
+
Subscribes to workflow events on the [PubSub](https://mastra.ai/docs/server/pubsub) bus and executes workflow steps. Every `workflow.start`, step transition, and lifecycle event flows through this worker.
|
|
29
|
+
|
|
30
|
+
In a split deployment, the orchestration worker pulls events from a distributed PubSub backend and delegates step execution back to the API over HTTP. In-process, it runs steps directly.
|
|
31
|
+
|
|
32
|
+
The orchestration worker requires a PubSub backend that supports pull mode (e.g., [`RedisStreamsPubSub`](https://mastra.ai/reference/pubsub/redis-streams) or [`GoogleCloudPubSub`](https://mastra.ai/reference/pubsub/google-cloud-pubsub)).
|
|
33
|
+
|
|
34
|
+
### Scheduler worker
|
|
35
|
+
|
|
36
|
+
Polls storage for due cron schedules and publishes `workflow.start` events. It is a producer only, meaning it creates work for the orchestration worker to pick up.
|
|
37
|
+
|
|
38
|
+
The scheduler reads declarative `schedule` fields from your workflow definitions automatically. See [Scheduled workflows](https://mastra.ai/docs/workflows/scheduled-workflows) for how to declare schedules.
|
|
39
|
+
|
|
40
|
+
**Do not run more than one scheduler instance.** Multiple schedulers polling the same storage would fire duplicate events for the same schedule.
|
|
41
|
+
|
|
42
|
+
### Background task worker
|
|
43
|
+
|
|
44
|
+
Executes agent tool calls marked with `background: { enabled: true }`. When an agent invokes a background tool, the API dispatches the task to this worker instead of blocking the response stream.
|
|
45
|
+
|
|
46
|
+
The background task worker manages concurrency limits, task lifecycle, and result delivery through the PubSub bus.
|
|
47
|
+
|
|
48
|
+
## How workers run
|
|
49
|
+
|
|
50
|
+
### In-process (default)
|
|
51
|
+
|
|
52
|
+
With no configuration, Mastra creates and starts workers inside the API process. Events flow through an in-memory PubSub, and everything shares a single Node.js runtime.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { Mastra } from '@mastra/core/mastra'
|
|
56
|
+
|
|
57
|
+
export const mastra = new Mastra({
|
|
58
|
+
// Workers run in-process by default.
|
|
59
|
+
// No pubsub or worker config needed.
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This setup needs no external infrastructure beyond your storage adapter. It doesn't survive process crashes, and you can't scale individual components.
|
|
64
|
+
|
|
65
|
+
### Split processes
|
|
66
|
+
|
|
67
|
+
To run workers separately, configure a distributed [PubSub](https://mastra.ai/docs/server/pubsub) backend and use the `MASTRA_WORKERS` environment variable to control which workers start in each process.
|
|
68
|
+
|
|
69
|
+
**Redis Streams + PostgreSQL**:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { Mastra } from '@mastra/core/mastra'
|
|
73
|
+
import { RedisStreamsPubSub } from '@mastra/redis-streams'
|
|
74
|
+
import { PostgresStore } from '@mastra/pg'
|
|
75
|
+
|
|
76
|
+
export const mastra = new Mastra({
|
|
77
|
+
storage: new PostgresStore({
|
|
78
|
+
connectionString: process.env.DATABASE_URL!,
|
|
79
|
+
}),
|
|
80
|
+
pubsub: new RedisStreamsPubSub({
|
|
81
|
+
url: process.env.REDIS_URL!,
|
|
82
|
+
}),
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Google Cloud Pub/Sub + LibSQL**:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { Mastra } from '@mastra/core/mastra'
|
|
90
|
+
import { GoogleCloudPubSub } from '@mastra/google-cloud-pubsub'
|
|
91
|
+
import { LibSQLStore } from '@mastra/libsql'
|
|
92
|
+
|
|
93
|
+
export const mastra = new Mastra({
|
|
94
|
+
storage: new LibSQLStore({
|
|
95
|
+
url: process.env.DATABASE_URL!,
|
|
96
|
+
}),
|
|
97
|
+
pubsub: new GoogleCloudPubSub({
|
|
98
|
+
projectId: process.env.GCP_PROJECT_ID!,
|
|
99
|
+
}),
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Any [supported storage backend](https://mastra.ai/reference/workers/overview) works — swap the storage adapter for your preferred database.
|
|
104
|
+
|
|
105
|
+
Run the same build artifact in multiple containers, each with a different [`MASTRA_WORKERS`](https://mastra.ai/reference/workers/overview) value to control which worker starts in each process.
|
|
106
|
+
|
|
107
|
+
Split deployments require a distributed PubSub backend ([`RedisStreamsPubSub`](https://mastra.ai/reference/pubsub/redis-streams) or [`GoogleCloudPubSub`](https://mastra.ai/reference/pubsub/google-cloud-pubsub)), a shared [storage backend](https://mastra.ai/reference/workers/overview), and network connectivity between the orchestration worker and the API.
|
|
108
|
+
|
|
109
|
+
The [worker deployment guide](https://mastra.ai/guides/deployment/mastra-workers) walks through this setup with a Docker Compose example.
|
|
110
|
+
|
|
111
|
+
## Network architecture
|
|
112
|
+
|
|
113
|
+
Workers are internal infrastructure. They are not exposed to end users and do not need their own subdomain, public URL, or inbound HTTP route.
|
|
114
|
+
|
|
115
|
+
In a split deployment:
|
|
116
|
+
|
|
117
|
+
- **The API server is the only public-facing process.** It serves all client HTTP requests — REST endpoints, agent interactions, workflow triggers, and any custom routes.
|
|
118
|
+
- **Workers connect outbound only.** They pull events from the distributed PubSub backend and read/write to the shared storage database. They do not accept inbound traffic from clients.
|
|
119
|
+
- **The orchestration worker calls the API internally.** It sends step execution requests to the API over the container network using `MASTRA_STEP_EXECUTION_URL`. This is internal service-to-service communication, not a public endpoint.
|
|
120
|
+
|
|
121
|
+
All three worker types (orchestration, scheduler, background task) sit behind the API on a private network. They share access to the PubSub backend and storage database but never receive traffic directly from clients. If a worker-related feature needs an HTTP route (for example, token minting for a voice integration), that route runs on the API server, not on the worker process.
|
|
122
|
+
|
|
123
|
+
## Known limitations
|
|
124
|
+
|
|
125
|
+
- **No dead-letter queue**: Failed events are nacked and retried, but there is no DLQ for events that repeatedly fail.
|
|
126
|
+
- **No built-in health endpoint**: Workers don't expose an HTTP health check. Use container-level liveness probes or process monitoring.
|
|
127
|
+
- **Scheduler is single-instance**: Running multiple scheduler processes causes duplicate schedule fires.
|
|
128
|
+
- **Runs stuck in "running" after API crash**: If the API process crashes while executing a workflow step, the run remains in `running` status with no automatic retry. For [durable agents](https://mastra.ai/docs/long-running-agents/durable-agents), set `recovery.durableAgents` to `'auto'` in the Mastra config to automatically re-drive orphaned runs on server restart. See [Crash recovery](https://mastra.ai/docs/long-running-agents/durable-agents) for details.
|
|
129
|
+
|
|
130
|
+
## Related
|
|
131
|
+
|
|
132
|
+
- [Worker deployment guide](https://mastra.ai/guides/deployment/mastra-workers): Docker Compose example and topology options
|
|
133
|
+
- [Worker authentication](https://mastra.ai/docs/server/auth/workers): Secure worker-to-API communication
|
|
134
|
+
- [Workers reference](https://mastra.ai/reference/workers/overview): Environment variables, worker types, and storage backends
|
|
135
|
+
- [CLI reference](https://mastra.ai/reference/cli/mastra): `mastra worker build` and `mastra worker start`
|
|
136
|
+
- [PubSub](https://mastra.ai/docs/server/pubsub): Event delivery backends
|
|
137
|
+
- [Scheduled workflows](https://mastra.ai/docs/workflows/scheduled-workflows): Declare cron schedules on workflows
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# Memory processors
|
|
4
4
|
|
|
5
|
-
Memory processors transform and filter messages as they pass through an agent with memory enabled. They manage context window limits
|
|
5
|
+
Memory processors transform and filter messages as they pass through an agent with memory enabled. They manage context window limits and remove unnecessary content, plus optimize the information sent to the language model.
|
|
6
6
|
|
|
7
|
-
When memory is enabled on an agent, Mastra adds memory processors to the agent's processor pipeline. These processors retrieve message history
|
|
7
|
+
When memory is enabled on an agent, Mastra adds memory processors to the agent's processor pipeline. These processors retrieve message history and working memory, plus semantically relevant messages, then persist new messages after the model responds.
|
|
8
8
|
|
|
9
9
|
Memory processors are [processors](https://mastra.ai/docs/agents/processors) that operate specifically on memory-related messages and state.
|
|
10
10
|
|
|
@@ -47,7 +47,7 @@ const agent = new Agent({
|
|
|
47
47
|
id: 'test-agent',
|
|
48
48
|
name: 'Test Agent',
|
|
49
49
|
instructions: 'You are a helpful assistant',
|
|
50
|
-
model: 'openai/gpt-5.
|
|
50
|
+
model: 'openai/gpt-5.6-sol',
|
|
51
51
|
memory: new Memory({
|
|
52
52
|
storage: new LibSQLStore({
|
|
53
53
|
id: 'memory-store',
|
|
@@ -97,7 +97,7 @@ import { openai } from '@ai-sdk/openai'
|
|
|
97
97
|
const agent = new Agent({
|
|
98
98
|
name: 'semantic-agent',
|
|
99
99
|
instructions: 'You are a helpful assistant with semantic memory',
|
|
100
|
-
model: 'openai/gpt-5.
|
|
100
|
+
model: 'openai/gpt-5.6-sol',
|
|
101
101
|
memory: new Memory({
|
|
102
102
|
storage: new LibSQLStore({
|
|
103
103
|
id: 'memory-store',
|
|
@@ -150,7 +150,7 @@ import { openai } from '@ai-sdk/openai'
|
|
|
150
150
|
const agent = new Agent({
|
|
151
151
|
name: 'working-memory-agent',
|
|
152
152
|
instructions: 'You are an assistant with working memory',
|
|
153
|
-
model: 'openai/gpt-5.
|
|
153
|
+
model: 'openai/gpt-5.6-sol',
|
|
154
154
|
memory: new Memory({
|
|
155
155
|
storage: new LibSQLStore({
|
|
156
156
|
id: 'memory-store',
|
|
@@ -182,7 +182,7 @@ const customMessageHistory = new MessageHistory({
|
|
|
182
182
|
const agent = new Agent({
|
|
183
183
|
name: 'custom-memory-agent',
|
|
184
184
|
instructions: 'You are a helpful assistant',
|
|
185
|
-
model: 'openai/gpt-5.
|
|
185
|
+
model: 'openai/gpt-5.6-sol',
|
|
186
186
|
memory: new Memory({
|
|
187
187
|
storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db' }),
|
|
188
188
|
lastMessages: 10, // This would normally add MessageHistory(10)
|
|
@@ -207,7 +207,7 @@ Understanding the execution order is important when combining guardrails with me
|
|
|
207
207
|
1. **Memory processors run FIRST**: `WorkingMemory`, `MessageHistory`, `SemanticRecall`
|
|
208
208
|
2. **Your input processors run AFTER**: guardrails, filters, validators
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
As a result, memory loads message history before your processors can validate or filter the input.
|
|
211
211
|
|
|
212
212
|
### Output Processors
|
|
213
213
|
|
|
@@ -253,7 +253,7 @@ const agent = new Agent({
|
|
|
253
253
|
id: 'safe-agent',
|
|
254
254
|
name: 'safe-agent',
|
|
255
255
|
instructions: 'You are a helpful assistant',
|
|
256
|
-
model: 'openai/gpt-5.
|
|
256
|
+
model: 'openai/gpt-5.6-sol',
|
|
257
257
|
memory: new Memory({ lastMessages: 10 }),
|
|
258
258
|
// Your guardrail runs BEFORE memory saves
|
|
259
259
|
outputProcessors: [contentBlocker],
|
|
@@ -293,7 +293,7 @@ const agent = new Agent({
|
|
|
293
293
|
id: 'validated-agent',
|
|
294
294
|
name: 'validated-agent',
|
|
295
295
|
instructions: 'You are a helpful assistant',
|
|
296
|
-
model: 'openai/gpt-5.
|
|
296
|
+
model: 'openai/gpt-5.6-sol',
|
|
297
297
|
memory: new Memory({ lastMessages: 10 }),
|
|
298
298
|
// Your guardrail runs AFTER memory loads history
|
|
299
299
|
inputProcessors: [inputValidator],
|
|
@@ -370,7 +370,7 @@ export const supportAgent = new Agent({
|
|
|
370
370
|
id: 'support-agent',
|
|
371
371
|
name: 'Support agent',
|
|
372
372
|
instructions: 'Answer customer support questions.',
|
|
373
|
-
model: 'openai/gpt-5.
|
|
373
|
+
model: 'openai/gpt-5.6-sol',
|
|
374
374
|
memory: new Memory({ lastMessages: 10 }),
|
|
375
375
|
inputProcessors: [new AttachmentUploader()],
|
|
376
376
|
})
|
|
@@ -124,7 +124,7 @@ You can use this history in two ways:
|
|
|
124
124
|
|
|
125
125
|
## Thread title generation
|
|
126
126
|
|
|
127
|
-
Mastra can automatically generate descriptive thread titles
|
|
127
|
+
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.
|
|
128
128
|
|
|
129
129
|
```typescript
|
|
130
130
|
import { Agent } from '@mastra/core/agent'
|
|
@@ -134,7 +134,7 @@ export const supportAgent = new Agent({
|
|
|
134
134
|
id: 'support-agent',
|
|
135
135
|
name: 'Support agent',
|
|
136
136
|
instructions: 'Answer customer support questions.',
|
|
137
|
-
model: 'openai/gpt-5.
|
|
137
|
+
model: 'openai/gpt-5.6-sol',
|
|
138
138
|
memory: new Memory({
|
|
139
139
|
options: {
|
|
140
140
|
generateTitle: true,
|
|
@@ -155,7 +155,7 @@ export const supportAgent = new Agent({
|
|
|
155
155
|
id: 'support-agent',
|
|
156
156
|
name: 'Support agent',
|
|
157
157
|
instructions: 'Answer customer support questions.',
|
|
158
|
-
model: 'openai/gpt-5.
|
|
158
|
+
model: 'openai/gpt-5.6-sol',
|
|
159
159
|
memory: new Memory({
|
|
160
160
|
options: {
|
|
161
161
|
generateTitle: {
|
|
@@ -176,7 +176,7 @@ const agent = mastra.getAgentById('test-agent')
|
|
|
176
176
|
const memory = await agent.getMemory()
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
The `Memory` instance gives you access to functions for listing threads
|
|
179
|
+
The `Memory` instance gives you access to functions for listing threads and recalling messages, plus cloning conversations, and more.
|
|
180
180
|
|
|
181
181
|
## Querying
|
|
182
182
|
|
|
@@ -263,6 +263,30 @@ const { messages } = await memory.recall({
|
|
|
263
263
|
})
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
+
Filter by shallow message metadata:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const { messages } = await memory.recall({
|
|
270
|
+
threadId: 'thread-123',
|
|
271
|
+
filter: {
|
|
272
|
+
metadata: {
|
|
273
|
+
category: 'billing',
|
|
274
|
+
escalated: true,
|
|
275
|
+
priority: 2,
|
|
276
|
+
archivedAt: null,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
})
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Metadata filters match shallow scalar values only: `string`, finite `number`, `boolean`, and `null`.
|
|
283
|
+
|
|
284
|
+
All specified metadata keys use AND semantics. A `null` filter matches only an explicit `null` value. A missing metadata key doesn't match.
|
|
285
|
+
|
|
286
|
+
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`.
|
|
287
|
+
|
|
288
|
+
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.
|
|
289
|
+
|
|
266
290
|
Fetch a single message by ID:
|
|
267
291
|
|
|
268
292
|
```typescript
|
|
@@ -306,7 +330,7 @@ Message queries return `MastraDBMessage[]` format. To display messages in a fron
|
|
|
306
330
|
|
|
307
331
|
## Thread cloning
|
|
308
332
|
|
|
309
|
-
Thread cloning creates a copy of an existing thread with its messages. This is useful for branching conversations
|
|
333
|
+
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.
|
|
310
334
|
|
|
311
335
|
```typescript
|
|
312
336
|
const { thread, clonedMessages } = await memory.cloneThread({
|
|
@@ -14,13 +14,13 @@ Use multi-user threads when several people collaborate on the same subject throu
|
|
|
14
14
|
|
|
15
15
|
## Share one `resourceId` across all participants
|
|
16
16
|
|
|
17
|
-
A thread belongs to exactly one `resourceId`, so all participants on a shared thread need to pass the same value. Instead of using a user id (the default for single-user apps), key `resourceId` on the conversation itself
|
|
17
|
+
A thread belongs to exactly one `resourceId`, so all participants on a shared thread need to pass the same value. Instead of using a user id (the default for single-user apps), key `resourceId` on the conversation itself, for example `doc_${docId}` for a shared document, or `room_${roomId}` for a group chat. With everyone pointing at the same `resourceId`, they read and write the same history.
|
|
18
18
|
|
|
19
19
|
## Tag each user message with the speaker's identity
|
|
20
20
|
|
|
21
21
|
The model needs to know who's talking on every turn. Since the message body is the one place that survives into history and back into context, wrap each user message in a small `<turn>` tag with the speaker's id, name, and role. The tag stays attached to the message, so when prior turns are recalled the model still sees who said what.
|
|
22
22
|
|
|
23
|
-
Build the tag with a small helper. The example below is one way to do it
|
|
23
|
+
Build the tag with a small helper. The example below is one way to do it, copy it into your project and adapt it to your shape of user data:
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
26
|
export type Speaker = {
|
|
@@ -113,11 +113,11 @@ The `<turn>` tag persists in the message body, so when history is recalled on la
|
|
|
113
113
|
|
|
114
114
|
The user-tagging pattern composes with every memory layer. Pick the layer based on how long the conversation needs to remember per-user facts:
|
|
115
115
|
|
|
116
|
-
- **Short conversations** (a single session, or a thread small enough to fit in `lastMessages`), or when you need a verbatim record of who said what: use [message history alone](#message-history-alone). The user tags in history are enough
|
|
116
|
+
- **Short conversations** (a single session, or a thread small enough to fit in `lastMessages`), or when you need a verbatim record of who said what: use [message history alone](#message-history-alone). The user tags in history are enough. No extra memory layer needed.
|
|
117
117
|
- **Long-running threads** (conversations that outgrow `lastMessages`, where you need per-user facts to survive history eviction): use [observational memory](#with-observational-memory-recommended).
|
|
118
118
|
- **Need a structured participants list, or your storage adapter doesn't support OM** (OM requires LibSQL, PG, or MongoDB): use [working memory](#with-working-memory).
|
|
119
119
|
|
|
120
|
-
We recommend using observational memory or working memory
|
|
120
|
+
We recommend using either observational memory or working memory because they cover overlapping needs. Running both adds latency and token cost without much benefit.
|
|
121
121
|
|
|
122
122
|
### Message history alone
|
|
123
123
|
|
|
@@ -139,7 +139,7 @@ The model reads identity from the `<turn>` tag on the current message and from p
|
|
|
139
139
|
|
|
140
140
|
### With Observational Memory (recommended)
|
|
141
141
|
|
|
142
|
-
[Observational Memory](https://mastra.ai/docs/memory/observational-memory) (OM) extracts per-user facts into a background log without burning the agent's tool budget. The default Observer model reads `<turn>` tags natively and produces
|
|
142
|
+
[Observational Memory](https://mastra.ai/docs/memory/observational-memory) (OM) extracts per-user facts into a background log without burning the agent's tool budget. The default Observer model reads `<turn>` tags natively and produces attribution like `Alice stated her favorite color is teal.` and `Bob asked for QA sign-off before publish.`
|
|
143
143
|
|
|
144
144
|
Prefer OM over working memory for multi-user threads when your storage supports it. OM extracts facts automatically, scales to any number of participants, and doesn't need template upkeep. Enable it with no overrides:
|
|
145
145
|
|
|
@@ -162,7 +162,7 @@ OM requires a storage adapter that supports it: `@mastra/libsql`, `@mastra/pg`,
|
|
|
162
162
|
|
|
163
163
|
### With working memory
|
|
164
164
|
|
|
165
|
-
Use working memory when OM isn't an option
|
|
165
|
+
Use working memory when OM isn't an option, for example, when your storage adapter doesn't support OM, or when you need a structured, deterministic participants list the agent can read and write on every turn.
|
|
166
166
|
|
|
167
167
|
The default [working memory](https://mastra.ai/docs/memory/working-memory) template assumes one user per thread ("First Name", "Last Name", etc.). For multi-user threads, provide a template with a participants list:
|
|
168
168
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Memory
|
|
4
4
|
|
|
5
|
-
Memory enables your agent to remember user messages
|
|
5
|
+
Memory enables your agent to remember user messages and agent replies, and tool results across interactions, giving it the context it needs to stay consistent, maintain conversation flow, plus produce better answers over time.
|
|
6
6
|
|
|
7
7
|
Mastra agents can be configured to store [message history](https://mastra.ai/docs/memory/message-history). Additionally, you can enable:
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ Memory results will be stored in one or more of your configured [storage provide
|
|
|
19
19
|
|
|
20
20
|
## When to use memory
|
|
21
21
|
|
|
22
|
-
Use memory when your agent needs to maintain multi-turn conversations that reference prior exchanges
|
|
22
|
+
Use memory when your agent needs to maintain multi-turn conversations that reference prior exchanges or recall user preferences or facts from earlier in a session, or alternatively build context over time within a conversation thread. Skip memory for single-turn requests where each interaction is independent.
|
|
23
23
|
|
|
24
24
|
## Quickstart
|
|
25
25
|
|
|
@@ -182,21 +182,21 @@ Each delegation creates a fresh `threadId` and a deterministic `resourceId` for
|
|
|
182
182
|
|
|
183
183
|
- **Thread ID**: Unique per delegation. The subagent starts with a clean message history every time it's called.
|
|
184
184
|
- **Resource ID**: Derived as `{parentResourceId}-{agentName}`. Because the resource ID is stable across delegations, resource-scoped memory persists between calls. A subagent remembers facts from previous delegations by the same user.
|
|
185
|
-
- **Memory instance**:
|
|
185
|
+
- **Memory instance**: A subagent without its own memory inherits the supervisor's `Memory` instance and all configured options. If the subagent defines its own, that takes precedence.
|
|
186
186
|
|
|
187
187
|
> **Note:** Title generation (`generateTitle`) is a top-level thread concern and **isn't** applied to inherited subagent threads. Because each delegation creates an ephemeral thread that no one sees, running title generation for it would waste an LLM call per delegation. To generate titles for a subagent's own threads, give that subagent its own memory configuration.
|
|
188
188
|
|
|
189
|
-
The supervisor forwards its conversation context to the subagent so it has enough background to complete the task. Only the delegation prompt and the subagent's response are saved
|
|
189
|
+
The supervisor forwards its conversation context to the subagent so it has enough background to complete the task. Only the delegation prompt and the subagent's response are saved, the full parent conversation isn't stored. You can control which messages reach the subagent with the [`messageFilter`](https://mastra.ai/docs/agents/supervisor-agents) callback.
|
|
190
190
|
|
|
191
|
-
> **Note:** Subagent resource IDs are always suffixed with the agent name (`{parentResourceId}-{agentName}`).
|
|
191
|
+
> **Note:** Subagent resource IDs are always suffixed with the agent name (`{parentResourceId}-{agentName}`). Different subagents under the same supervisor never share a resource ID through delegation.
|
|
192
192
|
|
|
193
193
|
To go beyond this default isolation, you can share memory between agents by passing matching identifiers when you call them directly.
|
|
194
194
|
|
|
195
195
|
### Share memory between agents
|
|
196
196
|
|
|
197
|
-
When you call agents directly (outside the delegation flow), memory sharing is controlled by two identifiers: `resourceId` and `threadId`. Agents that use the same values read and write to the same data. This is useful when agents collaborate on a shared context
|
|
197
|
+
When you call agents directly (outside the delegation flow), memory sharing is controlled by two identifiers: `resourceId` and `threadId`. Agents that use the same values read and write to the same data. This is useful when agents collaborate on a shared context, for example, a researcher that saves notes and a writer that reads them.
|
|
198
198
|
|
|
199
|
-
**Resource-scoped sharing** is the most common pattern. [Working memory](https://mastra.ai/docs/memory/working-memory) and [semantic recall](https://mastra.ai/docs/memory/semantic-recall) default to `scope: 'resource'`. If two agents share a `resourceId`, they share observations, working memory, and embeddings
|
|
199
|
+
**Resource-scoped sharing** is the most common pattern. [Working memory](https://mastra.ai/docs/memory/working-memory) and [semantic recall](https://mastra.ai/docs/memory/semantic-recall) default to `scope: 'resource'`. If two agents share a `resourceId`, they share observations, working memory, and embeddings, even across different threads:
|
|
200
200
|
|
|
201
201
|
```typescript
|
|
202
202
|
// Both agents share the same resource-scoped memory
|
|
@@ -209,15 +209,15 @@ await writer.generate('Write a summary from the research notes.', {
|
|
|
209
209
|
})
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
Because both calls use `resource: 'project-42'`, the writer can access the researcher's observations
|
|
212
|
+
Because both calls use `resource: 'project-42'`, the writer can access the researcher's observations and working memory. Semantic embeddings are also shared through the resource. Each agent still has its own thread, so message histories stay separate.
|
|
213
213
|
|
|
214
|
-
**Thread-scoped sharing** gives tighter coupling. [Observational Memory](https://mastra.ai/docs/memory/observational-memory) uses `scope: 'thread'` by default. If two agents use the same `resource`
|
|
214
|
+
**Thread-scoped sharing** gives tighter coupling. [Observational Memory](https://mastra.ai/docs/memory/observational-memory) uses `scope: 'thread'` by default. If two agents use the same `resource` and `thread`, they share the full message history. Each agent sees every message the other has written. This is useful when agents need to build on each other's exact outputs.
|
|
215
215
|
|
|
216
216
|
## Observability
|
|
217
217
|
|
|
218
218
|
Enable [Tracing](https://mastra.ai/docs/observability/tracing/overview) to monitor and debug memory in action. Traces show you exactly which messages and observations the agent included in its context for each request, helping you understand agent behavior and verify that memory retrieval is working as expected.
|
|
219
219
|
|
|
220
|
-
Open [Studio](https://mastra.ai/docs/studio/overview) and select the **Observability** tab in the sidebar. Open the trace of a recent agent request
|
|
220
|
+
Open [Studio](https://mastra.ai/docs/studio/overview) and select the **Observability** tab in the sidebar. Open the trace of a recent agent request and look for its LLM call spans.
|
|
221
221
|
|
|
222
222
|
## Switch memory per request
|
|
223
223
|
|
|
@@ -10,7 +10,7 @@ If you ask your friend what they did last weekend, they will search in their mem
|
|
|
10
10
|
|
|
11
11
|
Semantic recall is RAG-based search that helps agents maintain context across longer interactions when messages are no longer within [recent message history](https://mastra.ai/docs/memory/message-history).
|
|
12
12
|
|
|
13
|
-
It uses vector embeddings of messages for similarity search
|
|
13
|
+
It uses vector embeddings of messages for similarity search and integrates with vector stores, plus has configurable context windows around retrieved messages.
|
|
14
14
|
|
|
15
15
|

|
|
16
16
|
|
|
@@ -34,7 +34,7 @@ const agent = new Agent({
|
|
|
34
34
|
id: 'support-agent',
|
|
35
35
|
name: 'SupportAgent',
|
|
36
36
|
instructions: 'You are a helpful support agent.',
|
|
37
|
-
model: 'openai/gpt-5.
|
|
37
|
+
model: 'openai/gpt-5.6-sol',
|
|
38
38
|
memory: new Memory({
|
|
39
39
|
storage: new LibSQLStore({
|
|
40
40
|
id: 'agent-storage',
|
|
@@ -64,7 +64,7 @@ const agent = new Agent({
|
|
|
64
64
|
id: 'support-agent',
|
|
65
65
|
name: 'SupportAgent',
|
|
66
66
|
instructions: 'You are a helpful support agent.',
|
|
67
|
-
model: 'openai/gpt-5.
|
|
67
|
+
model: 'openai/gpt-5.6-sol',
|
|
68
68
|
memory: new Memory({
|
|
69
69
|
storage: new MongoDBStore({
|
|
70
70
|
id: 'agent-storage',
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
While [message history](https://mastra.ai/docs/memory/message-history) and [semantic recall](https://mastra.ai/docs/memory/semantic-recall) help agents remember conversations, working memory allows them to maintain persistent information about users across interactions.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Working memory is the agent's active scratchpad: key information it keeps available about the user or task. It can retain a person's name, preferences, or other important details during a conversation.
|
|
8
8
|
|
|
9
9
|
This is useful for maintaining ongoing state that's always relevant and should always be available to the agent.
|
|
10
10
|
|
|
@@ -17,7 +17,7 @@ Working memory can persist at two different scopes:
|
|
|
17
17
|
- **Resource-scoped** (default): Memory persists across all conversation threads for the same user
|
|
18
18
|
- **Thread-scoped**: Memory is isolated per conversation thread
|
|
19
19
|
|
|
20
|
-
**
|
|
20
|
+
**Requirement:** Switching between scopes means the agent won't see memory from the other scope - thread-scoped memory is completely separate from resource-scoped memory.
|
|
21
21
|
|
|
22
22
|
## Quickstart
|
|
23
23
|
|
|
@@ -32,7 +32,7 @@ const agent = new Agent({
|
|
|
32
32
|
id: 'personal-assistant',
|
|
33
33
|
name: 'PersonalAssistant',
|
|
34
34
|
instructions: 'You are a helpful personal assistant.',
|
|
35
|
-
model: 'openai/gpt-5.
|
|
35
|
+
model: 'openai/gpt-5.6-sol',
|
|
36
36
|
memory: new Memory({
|
|
37
37
|
options: {
|
|
38
38
|
workingMemory: {
|
|
@@ -45,7 +45,7 @@ const agent = new Agent({
|
|
|
45
45
|
|
|
46
46
|
## How it works
|
|
47
47
|
|
|
48
|
-
Working memory is a block of Markdown text that the agent
|
|
48
|
+
Working memory is a block of Markdown text that the agent can update over time to store continuously relevant information.
|
|
49
49
|
|
|
50
50
|
## Memory persistence scopes
|
|
51
51
|
|
|
@@ -134,7 +134,7 @@ Resource-scoped working memory requires specific storage adapters that support t
|
|
|
134
134
|
|
|
135
135
|
## Custom templates
|
|
136
136
|
|
|
137
|
-
Templates guide the agent on what information to track and update in working memory.
|
|
137
|
+
Templates guide the agent on what information to track and update in working memory. Mastra uses a default template when you don't provide one. Define a custom template for your agent's use case so it remembers the most relevant information. For threads shared by multiple users, see [Multi-user threads](https://mastra.ai/docs/memory/multi-user-threads).
|
|
138
138
|
|
|
139
139
|
Here's an example of a custom template. In this example the agent will store the users name, location, timezone, etc as soon as the user sends a message containing any of the info:
|
|
140
140
|
|
|
@@ -214,7 +214,7 @@ const paragraphMemory = new Memory({
|
|
|
214
214
|
|
|
215
215
|
Working memory can also be defined using a structured schema instead of a Markdown template. This allows you to specify the exact fields and types that should be tracked, using a [Standard JSON Schema](https://standardschema.dev/json-schema) ([Zod](https://zod.dev/), [Valibot](https://valibot.dev/), [ArkType](https://arktype.io/), etc.). When using a schema, the agent will see and update working memory as a JSON object matching your schema.
|
|
216
216
|
|
|
217
|
-
**
|
|
217
|
+
**Requirement:** You must specify either `template` or `schema`, but not both.
|
|
218
218
|
|
|
219
219
|
### Example: Schema-Based Working Memory
|
|
220
220
|
|
|
@@ -271,8 +271,8 @@ Schema-based working memory uses **merge semantics**, meaning the agent only nee
|
|
|
271
271
|
|
|
272
272
|
## Choosing between template and schema
|
|
273
273
|
|
|
274
|
-
- Use a **template** (Markdown) if you want the agent to maintain memory as a free-form text block, such as a user profile or scratchpad. Templates use **replace semantics
|
|
275
|
-
- Use a **schema** if you need structured, type-safe data that can be validated and programmatically accessed as JSON. The `workingMemory.schema` field accepts any `PublicSchema`-compatible schema (including Zod v3, Zod v4, JSON Schema, or already-standard schemas). Schemas use **merge semantics
|
|
274
|
+
- Use a **template** (Markdown) if you want the agent to maintain memory as a free-form text block, such as a user profile or scratchpad. Templates use **replace semantics**: the agent must provide the complete memory content on each update.
|
|
275
|
+
- Use a **schema** if you need structured, type-safe data that can be validated and programmatically accessed as JSON. The `workingMemory.schema` field accepts any `PublicSchema`-compatible schema (including Zod v3, Zod v4, JSON Schema, or already-standard schemas). Schemas use **merge semantics**: the agent only provides fields to update, and existing fields are preserved.
|
|
276
276
|
- Only one mode can be active at a time: setting both `template` and `schema` isn't supported.
|
|
277
277
|
|
|
278
278
|
## Example: Multi-step retention
|