@mastra/libsql 0.0.0-workflow-timeout-issue-20260220185702 → 0.0.0-workflow-graph-crash-20260527191009
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 +1085 -3
- package/LICENSE.md +15 -0
- package/dist/docs/SKILL.md +18 -19
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-agent-builder-deploying.md +121 -0
- package/dist/docs/references/docs-agent-builder-overview.md +97 -0
- package/dist/docs/references/docs-agents-agent-approval.md +336 -202
- package/dist/docs/references/docs-agents-networks.md +107 -215
- package/dist/docs/references/docs-memory-memory-processors.md +86 -88
- package/dist/docs/references/docs-memory-message-history.md +71 -63
- package/dist/docs/references/docs-memory-multi-user-threads.md +206 -0
- package/dist/docs/references/docs-memory-overview.md +221 -24
- package/dist/docs/references/docs-memory-semantic-recall.md +162 -75
- package/dist/docs/references/docs-memory-storage.md +72 -73
- package/dist/docs/references/docs-memory-working-memory.md +62 -62
- package/dist/docs/references/docs-rag-retrieval.md +132 -135
- package/dist/docs/references/docs-workflows-snapshots.md +31 -31
- package/dist/docs/references/guides-agent-frameworks-ai-sdk.md +36 -36
- package/dist/docs/references/reference-core-getMemory.md +15 -16
- package/dist/docs/references/reference-core-listMemory.md +17 -18
- package/dist/docs/references/reference-core-mastra-class.md +37 -27
- package/dist/docs/references/reference-memory-memory-class.md +41 -43
- package/dist/docs/references/reference-storage-composite.md +65 -55
- package/dist/docs/references/reference-storage-dynamodb.md +36 -36
- package/dist/docs/references/reference-storage-libsql.md +27 -27
- package/dist/docs/references/reference-vectors-libsql.md +72 -72
- package/dist/index.cjs +7896 -3257
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7888 -3259
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +14 -1
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/db/utils.d.ts +16 -0
- package/dist/storage/db/utils.d.ts.map +1 -1
- package/dist/storage/domains/agents/index.d.ts.map +1 -1
- package/dist/storage/domains/background-tasks/index.d.ts +18 -0
- package/dist/storage/domains/background-tasks/index.d.ts.map +1 -0
- package/dist/storage/domains/blobs/index.d.ts +17 -0
- package/dist/storage/domains/blobs/index.d.ts.map +1 -0
- package/dist/storage/domains/channels/index.d.ts +20 -0
- package/dist/storage/domains/channels/index.d.ts.map +1 -0
- package/dist/storage/domains/datasets/index.d.ts +43 -0
- package/dist/storage/domains/datasets/index.d.ts.map +1 -0
- package/dist/storage/domains/experiments/index.d.ts +31 -0
- package/dist/storage/domains/experiments/index.d.ts.map +1 -0
- package/dist/storage/domains/favorites/index.d.ts +17 -0
- package/dist/storage/domains/favorites/index.d.ts.map +1 -0
- package/dist/storage/domains/mcp-clients/index.d.ts.map +1 -1
- package/dist/storage/domains/mcp-servers/index.d.ts +26 -0
- package/dist/storage/domains/mcp-servers/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +7 -3
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +2 -1
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/prompt-blocks/index.d.ts.map +1 -1
- package/dist/storage/domains/schedules/index.d.ts +19 -0
- package/dist/storage/domains/schedules/index.d.ts.map +1 -0
- package/dist/storage/domains/scorer-definitions/index.d.ts.map +1 -1
- package/dist/storage/domains/skills/index.d.ts +26 -0
- package/dist/storage/domains/skills/index.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +1 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/domains/workspaces/index.d.ts +26 -0
- package/dist/storage/domains/workspaces/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +38 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts +14 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +12 -12
- package/dist/docs/references/docs-agents-agent-memory.md +0 -212
- package/dist/docs/references/docs-agents-network-approval.md +0 -275
- package/dist/docs/references/docs-observability-overview.md +0 -70
- package/dist/docs/references/docs-observability-tracing-exporters-default.md +0 -211
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
# Storage
|
|
2
2
|
|
|
3
|
-
For agents to remember previous interactions, Mastra needs a
|
|
3
|
+
For agents to remember previous interactions, Mastra needs a storage adapter. Use one of the [supported providers](#supported-providers) and pass it to your Mastra instance.
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
import { Mastra } from
|
|
7
|
-
import { LibSQLStore } from
|
|
6
|
+
import { Mastra } from '@mastra/core'
|
|
7
|
+
import { LibSQLStore } from '@mastra/libsql'
|
|
8
8
|
|
|
9
9
|
export const mastra = new Mastra({
|
|
10
10
|
storage: new LibSQLStore({
|
|
11
11
|
id: 'mastra-storage',
|
|
12
|
-
url:
|
|
12
|
+
url: 'file:./mastra.db',
|
|
13
13
|
}),
|
|
14
|
-
})
|
|
14
|
+
})
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
> **Sharing the database with
|
|
17
|
+
> **Sharing the database with Studio:** When running `mastra dev` alongside your application (e.g., Next.js), use an absolute path to ensure both processes access the same database:
|
|
18
18
|
>
|
|
19
19
|
> ```typescript
|
|
20
|
-
> url:
|
|
20
|
+
> url: 'file:/absolute/path/to/your/project/mastra.db'
|
|
21
21
|
> ```
|
|
22
22
|
>
|
|
23
23
|
> Relative paths like `file:./mastra.db` resolve based on each process's working directory, which may differ.
|
|
24
24
|
|
|
25
25
|
This configures instance-level storage, which all agents share by default. You can also configure [agent-level storage](#agent-level-storage) for isolated data boundaries.
|
|
26
26
|
|
|
27
|
-
Mastra automatically
|
|
27
|
+
Mastra automatically initializes the necessary storage structures on first interaction. See [Storage Overview](https://mastra.ai/reference/storage/overview) for domain coverage and the schema used by the built-in database-backed domains.
|
|
28
28
|
|
|
29
29
|
## Supported providers
|
|
30
30
|
|
|
@@ -34,8 +34,9 @@ Each provider page includes installation instructions, configuration parameters,
|
|
|
34
34
|
- [PostgreSQL](https://mastra.ai/reference/storage/postgresql)
|
|
35
35
|
- [MongoDB](https://mastra.ai/reference/storage/mongodb)
|
|
36
36
|
- [Upstash](https://mastra.ai/reference/storage/upstash)
|
|
37
|
+
- [Redis](https://mastra.ai/reference/storage/redis)
|
|
37
38
|
- [Cloudflare D1](https://mastra.ai/reference/storage/cloudflare-d1)
|
|
38
|
-
- [Cloudflare Durable Objects](https://mastra.ai/reference/storage/cloudflare)
|
|
39
|
+
- [Cloudflare KV & Durable Objects](https://mastra.ai/reference/storage/cloudflare)
|
|
39
40
|
- [Convex](https://mastra.ai/reference/storage/convex)
|
|
40
41
|
- [DynamoDB](https://mastra.ai/reference/storage/dynamodb)
|
|
41
42
|
- [LanceDB](https://mastra.ai/reference/storage/lance)
|
|
@@ -49,42 +50,42 @@ Storage can be configured at the instance level (shared by all agents) or at the
|
|
|
49
50
|
|
|
50
51
|
### Instance-level storage
|
|
51
52
|
|
|
52
|
-
Add storage to your Mastra instance so all agents, workflows, observability traces and scores share the same
|
|
53
|
+
Add storage to your Mastra instance so all agents, workflows, observability traces, and scores share the same storage backend:
|
|
53
54
|
|
|
54
55
|
```typescript
|
|
55
|
-
import { Mastra } from
|
|
56
|
-
import { PostgresStore } from
|
|
56
|
+
import { Mastra } from '@mastra/core'
|
|
57
|
+
import { PostgresStore } from '@mastra/pg'
|
|
57
58
|
|
|
58
59
|
export const mastra = new Mastra({
|
|
59
60
|
storage: new PostgresStore({
|
|
60
61
|
id: 'mastra-storage',
|
|
61
62
|
connectionString: process.env.DATABASE_URL,
|
|
62
63
|
}),
|
|
63
|
-
})
|
|
64
|
+
})
|
|
64
65
|
|
|
65
66
|
// Both agents inherit storage from the Mastra instance above
|
|
66
|
-
const agent1 = new Agent({ id:
|
|
67
|
-
const agent2 = new Agent({ id:
|
|
67
|
+
const agent1 = new Agent({ id: 'agent-1', memory: new Memory() })
|
|
68
|
+
const agent2 = new Agent({ id: 'agent-2', memory: new Memory() })
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
This is useful when all primitives share the same storage backend and have similar performance, scaling, and operational requirements.
|
|
71
72
|
|
|
72
73
|
#### Composite storage
|
|
73
74
|
|
|
74
|
-
[Composite storage](https://mastra.ai/reference/storage/composite) is an alternative way to configure instance-level storage. Use `MastraCompositeStore` to
|
|
75
|
+
[Composite storage](https://mastra.ai/reference/storage/composite) is an alternative way to configure instance-level storage. Use `MastraCompositeStore` to route `memory` and any other [supported domains](https://mastra.ai/reference/storage/composite) to different storage providers.
|
|
75
76
|
|
|
76
77
|
```typescript
|
|
77
|
-
import { Mastra } from
|
|
78
|
-
import { MastraCompositeStore } from
|
|
79
|
-
import { MemoryLibSQL } from
|
|
80
|
-
import { WorkflowsPG } from
|
|
81
|
-
import { ObservabilityStorageClickhouse } from
|
|
78
|
+
import { Mastra } from '@mastra/core'
|
|
79
|
+
import { MastraCompositeStore } from '@mastra/core/storage'
|
|
80
|
+
import { MemoryLibSQL } from '@mastra/libsql'
|
|
81
|
+
import { WorkflowsPG } from '@mastra/pg'
|
|
82
|
+
import { ObservabilityStorageClickhouse } from '@mastra/clickhouse'
|
|
82
83
|
|
|
83
84
|
export const mastra = new Mastra({
|
|
84
85
|
storage: new MastraCompositeStore({
|
|
85
|
-
id:
|
|
86
|
+
id: 'composite',
|
|
86
87
|
domains: {
|
|
87
|
-
memory: new MemoryLibSQL({ url:
|
|
88
|
+
memory: new MemoryLibSQL({ url: 'file:./memory.db' }),
|
|
88
89
|
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
|
|
89
90
|
observability: new ObservabilityStorageClickhouse({
|
|
90
91
|
url: process.env.CLICKHOUSE_URL,
|
|
@@ -93,65 +94,63 @@ export const mastra = new Mastra({
|
|
|
93
94
|
}),
|
|
94
95
|
},
|
|
95
96
|
}),
|
|
96
|
-
})
|
|
97
|
+
})
|
|
97
98
|
```
|
|
98
99
|
|
|
99
100
|
This is useful when different types of data have different performance or operational requirements, such as low-latency storage for memory, durable storage for workflows, and high-throughput storage for observability.
|
|
100
101
|
|
|
101
102
|
### Agent-level storage
|
|
102
103
|
|
|
103
|
-
Agent-level storage overrides storage configured at the instance level. Add storage to a specific agent when you need data
|
|
104
|
+
Agent-level storage overrides storage configured at the instance level. Add storage to a specific agent when you need to keep data separate or use different providers per agent.
|
|
104
105
|
|
|
105
106
|
```typescript
|
|
106
|
-
import { Agent } from
|
|
107
|
-
import { Memory } from
|
|
108
|
-
import { PostgresStore } from
|
|
107
|
+
import { Agent } from '@mastra/core/agent'
|
|
108
|
+
import { Memory } from '@mastra/memory'
|
|
109
|
+
import { PostgresStore } from '@mastra/pg'
|
|
109
110
|
|
|
110
111
|
export const agent = new Agent({
|
|
111
|
-
id:
|
|
112
|
+
id: 'agent',
|
|
112
113
|
memory: new Memory({
|
|
113
114
|
storage: new PostgresStore({
|
|
114
115
|
id: 'agent-storage',
|
|
115
116
|
connectionString: process.env.AGENT_DATABASE_URL,
|
|
116
117
|
}),
|
|
117
118
|
}),
|
|
118
|
-
})
|
|
119
|
+
})
|
|
119
120
|
```
|
|
120
121
|
|
|
121
|
-
> **Warning:** [Mastra Cloud Store](https://mastra.ai/docs/mastra-cloud/deployment) doesn't support agent-level storage.
|
|
122
|
-
|
|
123
122
|
## Threads and resources
|
|
124
123
|
|
|
125
124
|
Mastra organizes conversations using two identifiers:
|
|
126
125
|
|
|
127
|
-
- **Thread
|
|
128
|
-
- **Resource
|
|
126
|
+
- **Thread**: A conversation session containing a sequence of messages.
|
|
127
|
+
- **Resource**: The entity that owns the thread, such as a user, organization, project, or any other domain entity in your application.
|
|
129
128
|
|
|
130
129
|
Both identifiers are required for agents to store information:
|
|
131
130
|
|
|
132
|
-
|
|
131
|
+
**.generate()**:
|
|
133
132
|
|
|
134
133
|
```typescript
|
|
135
|
-
const response = await agent.generate(
|
|
134
|
+
const response = await agent.generate('hello', {
|
|
136
135
|
memory: {
|
|
137
|
-
thread:
|
|
138
|
-
resource:
|
|
136
|
+
thread: 'conversation-abc-123',
|
|
137
|
+
resource: 'user_123',
|
|
139
138
|
},
|
|
140
|
-
})
|
|
139
|
+
})
|
|
141
140
|
```
|
|
142
141
|
|
|
143
|
-
|
|
142
|
+
**.stream()**:
|
|
144
143
|
|
|
145
144
|
```typescript
|
|
146
|
-
const stream = await agent.stream(
|
|
145
|
+
const stream = await agent.stream('hello', {
|
|
147
146
|
memory: {
|
|
148
|
-
thread:
|
|
149
|
-
resource:
|
|
147
|
+
thread: 'conversation-abc-123',
|
|
148
|
+
resource: 'user_123',
|
|
150
149
|
},
|
|
151
|
-
})
|
|
150
|
+
})
|
|
152
151
|
```
|
|
153
152
|
|
|
154
|
-
> **Note:** [Studio](https://mastra.ai/docs/
|
|
153
|
+
> **Note:** [Studio](https://mastra.ai/docs/studio/overview) automatically generates a thread and resource ID for you. When calling `stream()` or `generate()` yourself, remember to provide these identifiers explicitly.
|
|
155
154
|
|
|
156
155
|
### Thread title generation
|
|
157
156
|
|
|
@@ -161,31 +160,31 @@ Use this option when implementing a ChatGPT-style chat interface to render a tit
|
|
|
161
160
|
|
|
162
161
|
```typescript
|
|
163
162
|
export const agent = new Agent({
|
|
164
|
-
id:
|
|
163
|
+
id: 'agent',
|
|
165
164
|
memory: new Memory({
|
|
166
165
|
options: {
|
|
167
166
|
generateTitle: true,
|
|
168
167
|
},
|
|
169
168
|
}),
|
|
170
|
-
})
|
|
169
|
+
})
|
|
171
170
|
```
|
|
172
171
|
|
|
173
|
-
Title generation runs asynchronously after the agent responds and
|
|
172
|
+
Title generation runs asynchronously after the agent responds and doesn't affect response time.
|
|
174
173
|
|
|
175
174
|
To optimize cost or behavior, provide a smaller [`model`](https://mastra.ai/models) and custom `instructions`:
|
|
176
175
|
|
|
177
176
|
```typescript
|
|
178
177
|
export const agent = new Agent({
|
|
179
|
-
id:
|
|
178
|
+
id: 'agent',
|
|
180
179
|
memory: new Memory({
|
|
181
180
|
options: {
|
|
182
181
|
generateTitle: {
|
|
183
|
-
model:
|
|
184
|
-
instructions:
|
|
182
|
+
model: '__OPENAI_MODEL_MINI__',
|
|
183
|
+
instructions: 'Generate a 1 word title',
|
|
185
184
|
},
|
|
186
185
|
},
|
|
187
186
|
}),
|
|
188
|
-
})
|
|
187
|
+
})
|
|
189
188
|
```
|
|
190
189
|
|
|
191
190
|
## Semantic recall
|
|
@@ -207,41 +206,41 @@ PostgreSQL, MongoDB, and libSQL have higher limits and are generally unaffected.
|
|
|
207
206
|
To avoid this, use an input processor to upload attachments to external storage (S3, R2, GCS, [Convex file storage](https://docs.convex.dev/file-storage), etc.) and replace them with URL references before persistence.
|
|
208
207
|
|
|
209
208
|
```typescript
|
|
210
|
-
import type { Processor } from
|
|
211
|
-
import type { MastraDBMessage } from
|
|
209
|
+
import type { Processor } from '@mastra/core/processors'
|
|
210
|
+
import type { MastraDBMessage } from '@mastra/core/memory'
|
|
212
211
|
|
|
213
212
|
export class AttachmentUploader implements Processor {
|
|
214
|
-
id =
|
|
213
|
+
id = 'attachment-uploader'
|
|
215
214
|
|
|
216
215
|
async processInput({ messages }: { messages: MastraDBMessage[] }) {
|
|
217
|
-
return Promise.all(messages.map(
|
|
216
|
+
return Promise.all(messages.map(msg => this.processMessage(msg)))
|
|
218
217
|
}
|
|
219
218
|
|
|
220
219
|
async processMessage(msg: MastraDBMessage) {
|
|
221
|
-
const attachments = msg.content.experimental_attachments
|
|
222
|
-
if (!attachments?.length) return msg
|
|
220
|
+
const attachments = msg.content.experimental_attachments
|
|
221
|
+
if (!attachments?.length) return msg
|
|
223
222
|
|
|
224
223
|
const uploaded = await Promise.all(
|
|
225
|
-
attachments.map(async
|
|
224
|
+
attachments.map(async att => {
|
|
226
225
|
// Skip if already a URL
|
|
227
|
-
if (!att.url?.startsWith(
|
|
226
|
+
if (!att.url?.startsWith('data:')) return att
|
|
228
227
|
|
|
229
228
|
// Upload base64 data and replace with URL
|
|
230
|
-
const url = await this.upload(att.url, att.contentType)
|
|
231
|
-
return { ...att, url }
|
|
232
|
-
})
|
|
233
|
-
)
|
|
229
|
+
const url = await this.upload(att.url, att.contentType)
|
|
230
|
+
return { ...att, url }
|
|
231
|
+
}),
|
|
232
|
+
)
|
|
234
233
|
|
|
235
|
-
return { ...msg, content: { ...msg.content, experimental_attachments: uploaded } }
|
|
234
|
+
return { ...msg, content: { ...msg.content, experimental_attachments: uploaded } }
|
|
236
235
|
}
|
|
237
236
|
|
|
238
237
|
async upload(dataUri: string, contentType?: string): Promise<string> {
|
|
239
|
-
const base64 = dataUri.split(
|
|
240
|
-
const buffer = Buffer.from(base64,
|
|
238
|
+
const base64 = dataUri.split(',')[1]
|
|
239
|
+
const buffer = Buffer.from(base64, 'base64')
|
|
241
240
|
|
|
242
241
|
// Replace with your storage provider (S3, R2, GCS, Convex, etc.)
|
|
243
242
|
// return await s3.upload(buffer, contentType);
|
|
244
|
-
throw new Error(
|
|
243
|
+
throw new Error('Implement upload() with your storage provider')
|
|
245
244
|
}
|
|
246
245
|
}
|
|
247
246
|
```
|
|
@@ -249,13 +248,13 @@ export class AttachmentUploader implements Processor {
|
|
|
249
248
|
Use the processor with your agent:
|
|
250
249
|
|
|
251
250
|
```typescript
|
|
252
|
-
import { Agent } from
|
|
253
|
-
import { Memory } from
|
|
254
|
-
import { AttachmentUploader } from
|
|
251
|
+
import { Agent } from '@mastra/core/agent'
|
|
252
|
+
import { Memory } from '@mastra/memory'
|
|
253
|
+
import { AttachmentUploader } from './processors/attachment-uploader'
|
|
255
254
|
|
|
256
255
|
const agent = new Agent({
|
|
257
|
-
id:
|
|
256
|
+
id: 'my-agent',
|
|
258
257
|
memory: new Memory({ storage: yourStorage }),
|
|
259
258
|
inputProcessors: [new AttachmentUploader()],
|
|
260
|
-
})
|
|
259
|
+
})
|
|
261
260
|
```
|
|
@@ -13,20 +13,20 @@ Working memory can persist at two different scopes:
|
|
|
13
13
|
|
|
14
14
|
**Important:** Switching between scopes means the agent won't see memory from the other scope - thread-scoped memory is completely separate from resource-scoped memory.
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Quickstart
|
|
17
17
|
|
|
18
18
|
Here's a minimal example of setting up an agent with working memory:
|
|
19
19
|
|
|
20
20
|
```typescript
|
|
21
|
-
import { Agent } from
|
|
22
|
-
import { Memory } from
|
|
21
|
+
import { Agent } from '@mastra/core/agent'
|
|
22
|
+
import { Memory } from '@mastra/memory'
|
|
23
23
|
|
|
24
24
|
// Create agent with working memory enabled
|
|
25
25
|
const agent = new Agent({
|
|
26
|
-
id:
|
|
27
|
-
name:
|
|
28
|
-
instructions:
|
|
29
|
-
model:
|
|
26
|
+
id: 'personal-assistant',
|
|
27
|
+
name: 'PersonalAssistant',
|
|
28
|
+
instructions: 'You are a helpful personal assistant.',
|
|
29
|
+
model: 'openai/gpt-5.4',
|
|
30
30
|
memory: new Memory({
|
|
31
31
|
options: {
|
|
32
32
|
workingMemory: {
|
|
@@ -34,16 +34,16 @@ const agent = new Agent({
|
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
36
|
}),
|
|
37
|
-
})
|
|
37
|
+
})
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
## How it
|
|
40
|
+
## How it works
|
|
41
41
|
|
|
42
42
|
Working memory is a block of Markdown text that the agent is able to update over time to store continuously relevant information:
|
|
43
43
|
|
|
44
44
|
[YouTube video player](https://www.youtube-nocookie.com/embed/UMy_JHLf1n8)
|
|
45
45
|
|
|
46
|
-
## Memory
|
|
46
|
+
## Memory persistence scopes
|
|
47
47
|
|
|
48
48
|
Working memory can operate in two different scopes, allowing you to choose how memory persists across conversations:
|
|
49
49
|
|
|
@@ -57,7 +57,7 @@ const memory = new Memory({
|
|
|
57
57
|
options: {
|
|
58
58
|
workingMemory: {
|
|
59
59
|
enabled: true,
|
|
60
|
-
scope:
|
|
60
|
+
scope: 'resource', // Memory persists across all user threads
|
|
61
61
|
template: `# User Profile
|
|
62
62
|
- **Name**:
|
|
63
63
|
- **Location**:
|
|
@@ -67,7 +67,7 @@ const memory = new Memory({
|
|
|
67
67
|
`,
|
|
68
68
|
},
|
|
69
69
|
},
|
|
70
|
-
})
|
|
70
|
+
})
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
**Use cases:**
|
|
@@ -82,12 +82,12 @@ When using resource-scoped memory, make sure to pass the `resource` parameter in
|
|
|
82
82
|
|
|
83
83
|
```typescript
|
|
84
84
|
// Resource-scoped memory requires resource
|
|
85
|
-
const response = await agent.generate(
|
|
85
|
+
const response = await agent.generate('Hello!', {
|
|
86
86
|
memory: {
|
|
87
|
-
thread:
|
|
88
|
-
resource:
|
|
87
|
+
thread: 'conversation-123',
|
|
88
|
+
resource: 'user-alice-456', // Same user across different threads
|
|
89
89
|
},
|
|
90
|
-
})
|
|
90
|
+
})
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
### Thread-Scoped Memory
|
|
@@ -100,7 +100,7 @@ const memory = new Memory({
|
|
|
100
100
|
options: {
|
|
101
101
|
workingMemory: {
|
|
102
102
|
enabled: true,
|
|
103
|
-
scope:
|
|
103
|
+
scope: 'thread', // Memory is isolated per thread
|
|
104
104
|
template: `# User Profile
|
|
105
105
|
- **Name**:
|
|
106
106
|
- **Interests**:
|
|
@@ -108,7 +108,7 @@ const memory = new Memory({
|
|
|
108
108
|
`,
|
|
109
109
|
},
|
|
110
110
|
},
|
|
111
|
-
})
|
|
111
|
+
})
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
**Use cases:**
|
|
@@ -117,7 +117,7 @@ const memory = new Memory({
|
|
|
117
117
|
- Temporary or session-specific information
|
|
118
118
|
- Workflows where each thread needs working memory but threads are ephemeral and not related to each other
|
|
119
119
|
|
|
120
|
-
## Storage
|
|
120
|
+
## Storage adapter support
|
|
121
121
|
|
|
122
122
|
Resource-scoped working memory requires specific storage adapters that support the `mastra_resources` table:
|
|
123
123
|
|
|
@@ -128,9 +128,9 @@ Resource-scoped working memory requires specific storage adapters that support t
|
|
|
128
128
|
- **Upstash** (`@mastra/upstash`)
|
|
129
129
|
- **MongoDB** (`@mastra/mongodb`)
|
|
130
130
|
|
|
131
|
-
## Custom
|
|
131
|
+
## Custom templates
|
|
132
132
|
|
|
133
|
-
Templates guide the agent on what information to track and update in working memory. While a default template is used if none is provided, you'll typically want to define a custom template tailored to your agent's specific use case to ensure it remembers the most relevant information.
|
|
133
|
+
Templates guide the agent on what information to track and update in working memory. While a default template is used if none is provided, you'll typically want to define a custom template tailored to your agent's specific use case to ensure it remembers the most relevant information. For threads shared by multiple users, see [Multi-user threads](https://mastra.ai/docs/memory/multi-user-threads).
|
|
134
134
|
|
|
135
135
|
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:
|
|
136
136
|
|
|
@@ -142,7 +142,7 @@ const memory = new Memory({
|
|
|
142
142
|
template: `
|
|
143
143
|
# User Profile
|
|
144
144
|
|
|
145
|
-
## Personal
|
|
145
|
+
## Personal info
|
|
146
146
|
|
|
147
147
|
- Name:
|
|
148
148
|
- Location:
|
|
@@ -156,7 +156,7 @@ const memory = new Memory({
|
|
|
156
156
|
- [Deadline 1]: [Date]
|
|
157
157
|
- [Deadline 2]: [Date]
|
|
158
158
|
|
|
159
|
-
## Session
|
|
159
|
+
## Session state
|
|
160
160
|
|
|
161
161
|
- Last Task Discussed:
|
|
162
162
|
- Open Questions:
|
|
@@ -165,16 +165,16 @@ const memory = new Memory({
|
|
|
165
165
|
`,
|
|
166
166
|
},
|
|
167
167
|
},
|
|
168
|
-
})
|
|
168
|
+
})
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
## Designing
|
|
171
|
+
## Designing effective templates
|
|
172
172
|
|
|
173
|
-
A well-structured template keeps the information
|
|
173
|
+
A well-structured template keeps the information straightforward for the agent to parse and update. Treat the template as a short form that you want the assistant to keep up to date.
|
|
174
174
|
|
|
175
|
-
- **Short, focused labels.** Avoid paragraphs or very long headings. Keep labels brief (for example `## Personal Info` or `- Name:`) so updates are
|
|
175
|
+
- **Short, focused labels.** Avoid paragraphs or very long headings. Keep labels brief (for example `## Personal Info` or `- Name:`) so updates are readable and less likely to be truncated.
|
|
176
176
|
- **Use consistent casing.** Inconsistent capitalization (`Timezone:` vs `timezone:`) can cause messy updates. Stick to Title Case or lower case for headings and bullet labels.
|
|
177
|
-
- **Keep placeholder text
|
|
177
|
+
- **Keep placeholder text minimal.** Use hints such as `[e.g., Formal]` or `[Date]` to help the LLM fill in the correct spots.
|
|
178
178
|
- **Abbreviate very long values.** If you only need a short form, include guidance like `- Name: [First name or nickname]` or `- Address (short):` rather than the full legal text.
|
|
179
179
|
- **Mention update rules in `instructions`.** You can instruct how and when to fill or clear parts of the template directly in the agent's `instructions` field.
|
|
180
180
|
|
|
@@ -190,7 +190,7 @@ const basicMemory = new Memory({
|
|
|
190
190
|
template: `User Facts:\n- Name:\n- Favorite Color:\n- Current Topic:`,
|
|
191
191
|
},
|
|
192
192
|
},
|
|
193
|
-
})
|
|
193
|
+
})
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
You can also store the key facts in a short paragraph format if you prefer a more narrative style:
|
|
@@ -203,20 +203,20 @@ const paragraphMemory = new Memory({
|
|
|
203
203
|
template: `Important Details:\n\nKeep a short paragraph capturing the user's important facts (name, main goal, current task).`,
|
|
204
204
|
},
|
|
205
205
|
},
|
|
206
|
-
})
|
|
206
|
+
})
|
|
207
207
|
```
|
|
208
208
|
|
|
209
|
-
## Structured
|
|
209
|
+
## Structured working memory
|
|
210
210
|
|
|
211
|
-
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 [Zod](https://zod.dev/)
|
|
211
|
+
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.
|
|
212
212
|
|
|
213
213
|
**Important:** You must specify either `template` or `schema`, but not both.
|
|
214
214
|
|
|
215
215
|
### Example: Schema-Based Working Memory
|
|
216
216
|
|
|
217
217
|
```typescript
|
|
218
|
-
import { z } from
|
|
219
|
-
import { Memory } from
|
|
218
|
+
import { z } from 'zod'
|
|
219
|
+
import { Memory } from '@mastra/memory'
|
|
220
220
|
|
|
221
221
|
const userProfileSchema = z.object({
|
|
222
222
|
name: z.string().optional(),
|
|
@@ -229,7 +229,7 @@ const userProfileSchema = z.object({
|
|
|
229
229
|
deadlines: z.array(z.string()).optional(),
|
|
230
230
|
})
|
|
231
231
|
.optional(),
|
|
232
|
-
})
|
|
232
|
+
})
|
|
233
233
|
|
|
234
234
|
const memory = new Memory({
|
|
235
235
|
options: {
|
|
@@ -239,7 +239,7 @@ const memory = new Memory({
|
|
|
239
239
|
// template: ... (do not set)
|
|
240
240
|
},
|
|
241
241
|
},
|
|
242
|
-
})
|
|
242
|
+
})
|
|
243
243
|
```
|
|
244
244
|
|
|
245
245
|
When a schema is provided, the agent receives the working memory as a JSON object. For example:
|
|
@@ -263,22 +263,22 @@ Schema-based working memory uses **merge semantics**, meaning the agent only nee
|
|
|
263
263
|
|
|
264
264
|
- **Object fields are deep merged:** Only provided fields are updated; others remain unchanged
|
|
265
265
|
- **Set a field to `null` to delete it:** This explicitly removes the field from memory
|
|
266
|
-
- **Arrays are replaced entirely:** When an array field is provided, it replaces the existing array (arrays
|
|
266
|
+
- **Arrays are replaced entirely:** When an array field is provided, it replaces the existing array (arrays aren't merged element-by-element)
|
|
267
267
|
|
|
268
|
-
## Choosing
|
|
268
|
+
## Choosing between template and schema
|
|
269
269
|
|
|
270
270
|
- 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.
|
|
271
|
-
- Use a **schema** if you need structured, type-safe data that can be validated and programmatically accessed as JSON. Schemas use **merge semantics** — the agent only provides fields to update, and existing fields are preserved.
|
|
272
|
-
- Only one mode can be active at a time: setting both `template` and `schema`
|
|
271
|
+
- 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.
|
|
272
|
+
- Only one mode can be active at a time: setting both `template` and `schema` isn't supported.
|
|
273
273
|
|
|
274
|
-
## Example: Multi-step
|
|
274
|
+
## Example: Multi-step retention
|
|
275
275
|
|
|
276
276
|
Below is a simplified view of how the `User Profile` template updates across a short user conversation:
|
|
277
277
|
|
|
278
278
|
```nohighlight
|
|
279
279
|
# User Profile
|
|
280
280
|
|
|
281
|
-
## Personal
|
|
281
|
+
## Personal info
|
|
282
282
|
|
|
283
283
|
- Name:
|
|
284
284
|
- Location:
|
|
@@ -301,9 +301,9 @@ Below is a simplified view of how the `User Profile` template updates across a s
|
|
|
301
301
|
|
|
302
302
|
The agent can now refer to `Sam` or `Berlin` in later responses without requesting the information again because it has been stored in working memory.
|
|
303
303
|
|
|
304
|
-
If your agent
|
|
304
|
+
If your agent isn't properly updating working memory when you expect it to, you can add system instructions on _how_ and _when_ to use this template in your agent's `instructions` setting.
|
|
305
305
|
|
|
306
|
-
## Setting
|
|
306
|
+
## Setting initial working memory
|
|
307
307
|
|
|
308
308
|
While agents typically update working memory through the `updateWorkingMemory` tool, you can also set initial working memory programmatically when creating or updating threads. This is useful for injecting user data (like their name, preferences, or other info) that you want available to the agent without passing it in every request.
|
|
309
309
|
|
|
@@ -314,9 +314,9 @@ When creating a thread, you can provide initial working memory through the metad
|
|
|
314
314
|
```typescript
|
|
315
315
|
// Create a thread with initial working memory
|
|
316
316
|
const thread = await memory.createThread({
|
|
317
|
-
threadId:
|
|
318
|
-
resourceId:
|
|
319
|
-
title:
|
|
317
|
+
threadId: 'thread-123',
|
|
318
|
+
resourceId: 'user-456',
|
|
319
|
+
title: 'Medical Consultation',
|
|
320
320
|
metadata: {
|
|
321
321
|
workingMemory: `# Patient Profile
|
|
322
322
|
- Name: John Doe
|
|
@@ -326,15 +326,15 @@ const thread = await memory.createThread({
|
|
|
326
326
|
- Medical History: Hypertension (controlled)
|
|
327
327
|
`,
|
|
328
328
|
},
|
|
329
|
-
})
|
|
329
|
+
})
|
|
330
330
|
|
|
331
331
|
// The agent will now have access to this information in all messages
|
|
332
332
|
await agent.generate("What's my blood type?", {
|
|
333
333
|
memory: {
|
|
334
334
|
thread: thread.id,
|
|
335
|
-
resource:
|
|
335
|
+
resource: 'user-456',
|
|
336
336
|
},
|
|
337
|
-
})
|
|
337
|
+
})
|
|
338
338
|
// Response: "Your blood type is O+."
|
|
339
339
|
```
|
|
340
340
|
|
|
@@ -345,7 +345,7 @@ You can also update an existing thread's working memory:
|
|
|
345
345
|
```typescript
|
|
346
346
|
// Update thread metadata to add/modify working memory
|
|
347
347
|
await memory.updateThread({
|
|
348
|
-
id:
|
|
348
|
+
id: 'thread-123',
|
|
349
349
|
title: thread.title,
|
|
350
350
|
metadata: {
|
|
351
351
|
...thread.metadata,
|
|
@@ -357,7 +357,7 @@ await memory.updateThread({
|
|
|
357
357
|
- Medical History: Hypertension (controlled)
|
|
358
358
|
`,
|
|
359
359
|
},
|
|
360
|
-
})
|
|
360
|
+
})
|
|
361
361
|
```
|
|
362
362
|
|
|
363
363
|
### Direct Memory Update
|
|
@@ -366,13 +366,13 @@ Alternatively, use the `updateWorkingMemory` method directly:
|
|
|
366
366
|
|
|
367
367
|
```typescript
|
|
368
368
|
await memory.updateWorkingMemory({
|
|
369
|
-
threadId:
|
|
370
|
-
resourceId:
|
|
371
|
-
workingMemory:
|
|
372
|
-
})
|
|
369
|
+
threadId: 'thread-123',
|
|
370
|
+
resourceId: 'user-456', // Required for resource-scoped memory
|
|
371
|
+
workingMemory: 'Updated memory content...',
|
|
372
|
+
})
|
|
373
373
|
```
|
|
374
374
|
|
|
375
|
-
## Read-
|
|
375
|
+
## Read-only working memory
|
|
376
376
|
|
|
377
377
|
In some scenarios, you may want an agent to have access to working memory data without the ability to modify it. This is useful for:
|
|
378
378
|
|
|
@@ -382,19 +382,19 @@ In some scenarios, you may want an agent to have access to working memory data w
|
|
|
382
382
|
To enable read-only mode, set `readOnly: true` in the memory options:
|
|
383
383
|
|
|
384
384
|
```typescript
|
|
385
|
-
const response = await agent.generate(
|
|
385
|
+
const response = await agent.generate('What do you know about me?', {
|
|
386
386
|
memory: {
|
|
387
|
-
thread:
|
|
388
|
-
resource:
|
|
387
|
+
thread: 'conversation-123',
|
|
388
|
+
resource: 'user-alice-456',
|
|
389
389
|
options: {
|
|
390
390
|
readOnly: true, // Working memory is provided but cannot be updated
|
|
391
391
|
},
|
|
392
392
|
},
|
|
393
|
-
})
|
|
393
|
+
})
|
|
394
394
|
```
|
|
395
395
|
|
|
396
396
|
## Examples
|
|
397
397
|
|
|
398
398
|
- [Working memory with template](https://github.com/mastra-ai/mastra/tree/main/examples/memory-with-template)
|
|
399
399
|
- [Working memory with schema](https://github.com/mastra-ai/mastra/tree/main/examples/memory-with-schema)
|
|
400
|
-
- [Per-resource working memory](https://github.com/mastra-ai/mastra/tree/main/examples/memory-per-resource-example)
|
|
400
|
+
- [Per-resource working memory](https://github.com/mastra-ai/mastra/tree/main/examples/memory-per-resource-example): Complete example showing resource-scoped memory persistence
|