@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.
Files changed (73) hide show
  1. package/CHANGELOG.md +1085 -3
  2. package/LICENSE.md +15 -0
  3. package/dist/docs/SKILL.md +18 -19
  4. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  5. package/dist/docs/references/docs-agent-builder-deploying.md +121 -0
  6. package/dist/docs/references/docs-agent-builder-overview.md +97 -0
  7. package/dist/docs/references/docs-agents-agent-approval.md +336 -202
  8. package/dist/docs/references/docs-agents-networks.md +107 -215
  9. package/dist/docs/references/docs-memory-memory-processors.md +86 -88
  10. package/dist/docs/references/docs-memory-message-history.md +71 -63
  11. package/dist/docs/references/docs-memory-multi-user-threads.md +206 -0
  12. package/dist/docs/references/docs-memory-overview.md +221 -24
  13. package/dist/docs/references/docs-memory-semantic-recall.md +162 -75
  14. package/dist/docs/references/docs-memory-storage.md +72 -73
  15. package/dist/docs/references/docs-memory-working-memory.md +62 -62
  16. package/dist/docs/references/docs-rag-retrieval.md +132 -135
  17. package/dist/docs/references/docs-workflows-snapshots.md +31 -31
  18. package/dist/docs/references/guides-agent-frameworks-ai-sdk.md +36 -36
  19. package/dist/docs/references/reference-core-getMemory.md +15 -16
  20. package/dist/docs/references/reference-core-listMemory.md +17 -18
  21. package/dist/docs/references/reference-core-mastra-class.md +37 -27
  22. package/dist/docs/references/reference-memory-memory-class.md +41 -43
  23. package/dist/docs/references/reference-storage-composite.md +65 -55
  24. package/dist/docs/references/reference-storage-dynamodb.md +36 -36
  25. package/dist/docs/references/reference-storage-libsql.md +27 -27
  26. package/dist/docs/references/reference-vectors-libsql.md +72 -72
  27. package/dist/index.cjs +7896 -3257
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.js +7888 -3259
  30. package/dist/index.js.map +1 -1
  31. package/dist/storage/db/index.d.ts +14 -1
  32. package/dist/storage/db/index.d.ts.map +1 -1
  33. package/dist/storage/db/utils.d.ts +16 -0
  34. package/dist/storage/db/utils.d.ts.map +1 -1
  35. package/dist/storage/domains/agents/index.d.ts.map +1 -1
  36. package/dist/storage/domains/background-tasks/index.d.ts +18 -0
  37. package/dist/storage/domains/background-tasks/index.d.ts.map +1 -0
  38. package/dist/storage/domains/blobs/index.d.ts +17 -0
  39. package/dist/storage/domains/blobs/index.d.ts.map +1 -0
  40. package/dist/storage/domains/channels/index.d.ts +20 -0
  41. package/dist/storage/domains/channels/index.d.ts.map +1 -0
  42. package/dist/storage/domains/datasets/index.d.ts +43 -0
  43. package/dist/storage/domains/datasets/index.d.ts.map +1 -0
  44. package/dist/storage/domains/experiments/index.d.ts +31 -0
  45. package/dist/storage/domains/experiments/index.d.ts.map +1 -0
  46. package/dist/storage/domains/favorites/index.d.ts +17 -0
  47. package/dist/storage/domains/favorites/index.d.ts.map +1 -0
  48. package/dist/storage/domains/mcp-clients/index.d.ts.map +1 -1
  49. package/dist/storage/domains/mcp-servers/index.d.ts +26 -0
  50. package/dist/storage/domains/mcp-servers/index.d.ts.map +1 -0
  51. package/dist/storage/domains/memory/index.d.ts +7 -3
  52. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  53. package/dist/storage/domains/observability/index.d.ts +2 -1
  54. package/dist/storage/domains/observability/index.d.ts.map +1 -1
  55. package/dist/storage/domains/prompt-blocks/index.d.ts.map +1 -1
  56. package/dist/storage/domains/schedules/index.d.ts +19 -0
  57. package/dist/storage/domains/schedules/index.d.ts.map +1 -0
  58. package/dist/storage/domains/scorer-definitions/index.d.ts.map +1 -1
  59. package/dist/storage/domains/skills/index.d.ts +26 -0
  60. package/dist/storage/domains/skills/index.d.ts.map +1 -0
  61. package/dist/storage/domains/workflows/index.d.ts +1 -0
  62. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  63. package/dist/storage/domains/workspaces/index.d.ts +26 -0
  64. package/dist/storage/domains/workspaces/index.d.ts.map +1 -0
  65. package/dist/storage/index.d.ts +38 -1
  66. package/dist/storage/index.d.ts.map +1 -1
  67. package/dist/vector/index.d.ts +14 -1
  68. package/dist/vector/index.d.ts.map +1 -1
  69. package/package.json +12 -12
  70. package/dist/docs/references/docs-agents-agent-memory.md +0 -212
  71. package/dist/docs/references/docs-agents-network-approval.md +0 -275
  72. package/dist/docs/references/docs-observability-overview.md +0 -70
  73. 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 database. Use a storage adapter for one of the [supported databases](#supported-providers) and pass it to your Mastra instance.
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 "@mastra/core";
7
- import { LibSQLStore } from "@mastra/libsql";
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: "file:./mastra.db",
12
+ url: 'file:./mastra.db',
13
13
  }),
14
- });
14
+ })
15
15
  ```
16
16
 
17
- > **Sharing the database with Mastra Studio:** When running `mastra dev` alongside your application (e.g., Next.js), use an absolute path to ensure both processes access the same database:
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: "file:/absolute/path/to/your/project/mastra.db"
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 creates the necessary tables on first interaction. See the [core schema](https://mastra.ai/reference/storage/overview) for details on what gets created, including tables for messages, threads, resources, workflows, traces, and evaluation datasets.
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 memory provider:
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 "@mastra/core";
56
- import { PostgresStore } from "@mastra/pg";
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: "agent-1", memory: new Memory() });
67
- const agent2 = new Agent({ id: "agent-2", memory: new Memory() });
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 set the `memory` domain (and any other [domains](https://mastra.ai/reference/storage/composite) you need) to different storage providers.
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 "@mastra/core";
78
- import { MastraCompositeStore } from "@mastra/core/storage";
79
- import { MemoryLibSQL } from "@mastra/libsql";
80
- import { WorkflowsPG } from "@mastra/pg";
81
- import { ObservabilityStorageClickhouse } from "@mastra/clickhouse";
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: "composite",
86
+ id: 'composite',
86
87
  domains: {
87
- memory: new MemoryLibSQL({ url: "file:./memory.db" }),
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 boundaries or compliance requirements:
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 "@mastra/core/agent";
107
- import { Memory } from "@mastra/memory";
108
- import { PostgresStore } from "@mastra/pg";
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: "agent",
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** - a conversation session containing a sequence of messages.
128
- - **Resource** - the entity that owns the thread, such as a user, organization, project, or any other domain entity in your application.
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
- **Generate**:
131
+ **.generate()**:
133
132
 
134
133
  ```typescript
135
- const response = await agent.generate("hello", {
134
+ const response = await agent.generate('hello', {
136
135
  memory: {
137
- thread: "conversation-abc-123",
138
- resource: "user_123",
136
+ thread: 'conversation-abc-123',
137
+ resource: 'user_123',
139
138
  },
140
- });
139
+ })
141
140
  ```
142
141
 
143
- **Stream**:
142
+ **.stream()**:
144
143
 
145
144
  ```typescript
146
- const stream = await agent.stream("hello", {
145
+ const stream = await agent.stream('hello', {
147
146
  memory: {
148
- thread: "conversation-abc-123",
149
- resource: "user_123",
147
+ thread: 'conversation-abc-123',
148
+ resource: 'user_123',
150
149
  },
151
- });
150
+ })
152
151
  ```
153
152
 
154
- > **Note:** [Studio](https://mastra.ai/docs/getting-started/studio) automatically generates a thread and resource ID for you. When calling `stream()` or `generate()` yourself, remember to provide these identifiers explicitly.
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: "agent",
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 does not affect response time.
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: "agent",
178
+ id: 'agent',
180
179
  memory: new Memory({
181
180
  options: {
182
181
  generateTitle: {
183
- model: "openai/gpt-4o-mini",
184
- instructions: "Generate a 1 word title",
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 "@mastra/core/processors";
211
- import type { MastraDBMessage } from "@mastra/core/memory";
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 = "attachment-uploader";
213
+ id = 'attachment-uploader'
215
214
 
216
215
  async processInput({ messages }: { messages: MastraDBMessage[] }) {
217
- return Promise.all(messages.map((msg) => this.processMessage(msg)));
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 (att) => {
224
+ attachments.map(async att => {
226
225
  // Skip if already a URL
227
- if (!att.url?.startsWith("data:")) return att;
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(",")[1];
240
- const buffer = Buffer.from(base64, "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("Implement upload() with your storage provider");
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 "@mastra/core/agent";
253
- import { Memory } from "@mastra/memory";
254
- import { AttachmentUploader } from "./processors/attachment-uploader";
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: "my-agent",
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
- ## Quick Start
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 "@mastra/core/agent";
22
- import { Memory } from "@mastra/memory";
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: "personal-assistant",
27
- name: "PersonalAssistant",
28
- instructions: "You are a helpful personal assistant.",
29
- model: "openai/gpt-5.1",
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 Works
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 Persistence Scopes
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: "resource", // Memory persists across all user threads
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("Hello!", {
85
+ const response = await agent.generate('Hello!', {
86
86
  memory: {
87
- thread: "conversation-123",
88
- resource: "user-alice-456", // Same user across different threads
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: "thread", // Memory is isolated per thread
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 Adapter Support
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 Templates
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 Info
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 State
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 Effective Templates
171
+ ## Designing effective templates
172
172
 
173
- A well-structured template keeps the information easy for the agent to parse and update. Treat the template as a short form that you want the assistant to keep up to date.
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 easy to read and less likely to be truncated.
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 simple.** Use hints such as `[e.g., Formal]` or `[Date]` to help the LLM fill in the correct spots.
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 Working Memory
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/) schema. When using a schema, the agent will see and update working memory as a JSON object matching your schema.
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 "zod";
219
- import { Memory } from "@mastra/memory";
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 are not merged element-by-element)
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 Between Template and Schema
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` is not supported.
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 Retention
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 Info
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 is not 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.
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 Initial Working Memory
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: "thread-123",
318
- resourceId: "user-456",
319
- title: "Medical Consultation",
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: "user-456",
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: "thread-123",
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: "thread-123",
370
- resourceId: "user-456", // Required for resource-scoped memory
371
- workingMemory: "Updated memory content...",
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-Only Working Memory
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("What do you know about me?", {
385
+ const response = await agent.generate('What do you know about me?', {
386
386
  memory: {
387
- thread: "conversation-123",
388
- resource: "user-alice-456",
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) - Complete example showing resource-scoped memory persistence
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