@mastra/memory 0.0.0-error-handler-fix-20251020202607 → 0.0.0-esbuild-bundle-worker-20260807182016
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 +4656 -3
- package/LICENSE.md +15 -0
- package/README.md +26 -1
- package/dist/_types/@internal_ai-sdk-v4/dist/index.d.ts +7450 -0
- package/dist/docs/SKILL.md +62 -0
- package/dist/docs/assets/SOURCE_MAP.json +11 -0
- package/dist/docs/references/docs-agents-agent-approval.md +664 -0
- package/dist/docs/references/docs-agents-networks.md +184 -0
- package/dist/docs/references/docs-capabilities-subagents.md +454 -0
- package/dist/docs/references/docs-evals-evals-with-memory.md +146 -0
- package/dist/docs/references/docs-long-running-agents-background-tasks.md +382 -0
- package/dist/docs/references/docs-long-running-agents-goals.md +118 -0
- package/dist/docs/references/docs-memory-memory-processors.md +385 -0
- package/dist/docs/references/docs-memory-message-history.md +348 -0
- package/dist/docs/references/docs-memory-multi-user-threads.md +208 -0
- package/dist/docs/references/docs-memory-observational-memory.md +835 -0
- package/dist/docs/references/docs-memory-overview.md +266 -0
- package/dist/docs/references/docs-memory-semantic-recall.md +401 -0
- package/dist/docs/references/docs-memory-working-memory.md +431 -0
- package/dist/docs/references/docs-storage-overview.md +214 -0
- package/dist/docs/references/reference-core-getMemory.md +51 -0
- package/dist/docs/references/reference-core-listMemory.md +57 -0
- package/dist/docs/references/reference-file-based-agents-memory.md +58 -0
- package/dist/docs/references/reference-memory-clone-utilities.md +203 -0
- package/dist/docs/references/reference-memory-cloneThread.md +173 -0
- package/dist/docs/references/reference-memory-createThread.md +70 -0
- package/dist/docs/references/reference-memory-getThreadById.md +26 -0
- package/dist/docs/references/reference-memory-listThreads.md +147 -0
- package/dist/docs/references/reference-memory-memory-class.md +148 -0
- package/dist/docs/references/reference-memory-observational-memory.md +877 -0
- package/dist/docs/references/reference-memory-summarizeConversation.md +99 -0
- package/dist/docs/references/reference-memory-summarizeThread.md +93 -0
- package/dist/docs/references/reference-processors-token-limiter-processor.md +158 -0
- package/dist/docs/references/reference-storage-dsql.md +430 -0
- package/dist/docs/references/reference-storage-dynamodb.md +284 -0
- package/dist/docs/references/reference-storage-libsql.md +143 -0
- package/dist/docs/references/reference-storage-mongodb.md +267 -0
- package/dist/docs/references/reference-storage-postgresql.md +531 -0
- package/dist/docs/references/reference-storage-redis.md +268 -0
- package/dist/docs/references/reference-storage-upstash.md +162 -0
- package/dist/docs/references/reference-vectors-libsql.md +307 -0
- package/dist/docs/references/reference-vectors-mongodb.md +567 -0
- package/dist/docs/references/reference-vectors-pg.md +430 -0
- package/dist/docs/references/reference-vectors-upstash.md +296 -0
- package/dist/index.cjs +35 -893
- package/dist/index.d.ts +465 -62
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -887
- package/dist/processors/index.cjs +32 -165
- package/dist/processors/index.d.ts +1 -2
- package/dist/processors/index.d.ts.map +1 -1
- package/dist/processors/index.js +2 -158
- package/dist/processors/observational-memory/activation-ttl.d.ts +4 -0
- package/dist/processors/observational-memory/activation-ttl.d.ts.map +1 -0
- package/dist/processors/observational-memory/anchor-ids.d.ts +4 -0
- package/dist/processors/observational-memory/anchor-ids.d.ts.map +1 -0
- package/dist/processors/observational-memory/buffering-coordinator.d.ts +61 -0
- package/dist/processors/observational-memory/buffering-coordinator.d.ts.map +1 -0
- package/dist/processors/observational-memory/built-in-extractors.d.ts +15 -0
- package/dist/processors/observational-memory/built-in-extractors.d.ts.map +1 -0
- package/dist/processors/observational-memory/constants.d.ts +74 -0
- package/dist/processors/observational-memory/constants.d.ts.map +1 -0
- package/dist/processors/observational-memory/date-utils.d.ts +41 -0
- package/dist/processors/observational-memory/date-utils.d.ts.map +1 -0
- package/dist/processors/observational-memory/debug.d.ts +3 -0
- package/dist/processors/observational-memory/debug.d.ts.map +1 -0
- package/dist/processors/observational-memory/extracted-values.d.ts +44 -0
- package/dist/processors/observational-memory/extracted-values.d.ts.map +1 -0
- package/dist/processors/observational-memory/extraction-runner.d.ts +22 -0
- package/dist/processors/observational-memory/extraction-runner.d.ts.map +1 -0
- package/dist/processors/observational-memory/extractor.d.ts +76 -0
- package/dist/processors/observational-memory/extractor.d.ts.map +1 -0
- package/dist/processors/observational-memory/index.d.ts +30 -0
- package/dist/processors/observational-memory/index.d.ts.map +1 -0
- package/dist/processors/observational-memory/internal-request-context.d.ts +17 -0
- package/dist/processors/observational-memory/internal-request-context.d.ts.map +1 -0
- package/dist/processors/observational-memory/markers.d.ts +118 -0
- package/dist/processors/observational-memory/markers.d.ts.map +1 -0
- package/dist/processors/observational-memory/message-utils.d.ts +83 -0
- package/dist/processors/observational-memory/message-utils.d.ts.map +1 -0
- package/dist/processors/observational-memory/model-by-input-tokens.d.ts +14 -0
- package/dist/processors/observational-memory/model-by-input-tokens.d.ts.map +1 -0
- package/dist/processors/observational-memory/model-context.d.ts +2 -0
- package/dist/processors/observational-memory/model-context.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-groups.d.ts +15 -0
- package/dist/processors/observational-memory/observation-groups.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-strategies/async-buffer.d.ts +39 -0
- package/dist/processors/observational-memory/observation-strategies/async-buffer.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-strategies/base.d.ts +122 -0
- package/dist/processors/observational-memory/observation-strategies/base.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-strategies/index.d.ts +7 -0
- package/dist/processors/observational-memory/observation-strategies/index.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-strategies/resource-scoped.d.ts +43 -0
- package/dist/processors/observational-memory/observation-strategies/resource-scoped.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-strategies/sync.d.ts +41 -0
- package/dist/processors/observational-memory/observation-strategies/sync.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-strategies/types.d.ts +103 -0
- package/dist/processors/observational-memory/observation-strategies/types.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-turn/index.d.ts +4 -0
- package/dist/processors/observational-memory/observation-turn/index.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-turn/load-memory-context.d.ts +9 -0
- package/dist/processors/observational-memory/observation-turn/load-memory-context.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-turn/step.d.ts +53 -0
- package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-turn/turn.d.ts +139 -0
- package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-turn/types.d.ts +46 -0
- package/dist/processors/observational-memory/observation-turn/types.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-utils.d.ts +16 -0
- package/dist/processors/observational-memory/observation-utils.d.ts.map +1 -0
- package/dist/processors/observational-memory/observational-memory.d.ts +930 -0
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -0
- package/dist/processors/observational-memory/observer-agent.d.ts +190 -0
- package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -0
- package/dist/processors/observational-memory/observer-runner.d.ts +141 -0
- package/dist/processors/observational-memory/observer-runner.d.ts.map +1 -0
- package/dist/processors/observational-memory/operation-registry.d.ts +14 -0
- package/dist/processors/observational-memory/operation-registry.d.ts.map +1 -0
- package/dist/processors/observational-memory/processor.d.ts +70 -0
- package/dist/processors/observational-memory/processor.d.ts.map +1 -0
- package/dist/processors/observational-memory/reflector-agent.d.ts +62 -0
- package/dist/processors/observational-memory/reflector-agent.d.ts.map +1 -0
- package/dist/processors/observational-memory/reflector-runner.d.ts +133 -0
- package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -0
- package/dist/processors/observational-memory/repro-capture.d.ts +33 -0
- package/dist/processors/observational-memory/repro-capture.d.ts.map +1 -0
- package/dist/processors/observational-memory/retry.d.ts +63 -0
- package/dist/processors/observational-memory/retry.d.ts.map +1 -0
- package/dist/processors/observational-memory/string-utils.d.ts +13 -0
- package/dist/processors/observational-memory/string-utils.d.ts.map +1 -0
- package/dist/processors/observational-memory/summarize.d.ts +92 -0
- package/dist/processors/observational-memory/summarize.d.ts.map +1 -0
- package/dist/processors/observational-memory/temporal-markers.d.ts +4 -0
- package/dist/processors/observational-memory/temporal-markers.d.ts.map +1 -0
- package/dist/processors/observational-memory/temporary-memory.d.ts +8 -0
- package/dist/processors/observational-memory/temporary-memory.d.ts.map +1 -0
- package/dist/processors/observational-memory/thresholds.d.ts +52 -0
- package/dist/processors/observational-memory/thresholds.d.ts.map +1 -0
- package/dist/processors/observational-memory/token-counter.d.ts +57 -0
- package/dist/processors/observational-memory/token-counter.d.ts.map +1 -0
- package/dist/processors/observational-memory/tool-result-helpers.d.ts +12 -0
- package/dist/processors/observational-memory/tool-result-helpers.d.ts.map +1 -0
- package/dist/processors/observational-memory/tracing.d.ts +17 -0
- package/dist/processors/observational-memory/tracing.d.ts.map +1 -0
- package/dist/processors/observational-memory/types.d.ts +997 -0
- package/dist/processors/observational-memory/types.d.ts.map +1 -0
- package/dist/processors/observational-memory/working-memory-extractor.d.ts +5 -0
- package/dist/processors/observational-memory/working-memory-extractor.d.ts.map +1 -0
- package/dist/processors/working-memory-state/index.d.ts +2 -0
- package/dist/processors/working-memory-state/index.d.ts.map +1 -0
- package/dist/processors/working-memory-state/processor.d.ts +53 -0
- package/dist/processors/working-memory-state/processor.d.ts.map +1 -0
- package/dist/src-C1tlhGeW.js +28559 -0
- package/dist/src-C1tlhGeW.js.map +1 -0
- package/dist/src-DqoifKIy.cjs +28813 -0
- package/dist/src-DqoifKIy.cjs.map +1 -0
- package/dist/tools/om-tools.d.ts +172 -0
- package/dist/tools/om-tools.d.ts.map +1 -0
- package/dist/tools/working-memory.d.ts +33 -28
- package/dist/tools/working-memory.d.ts.map +1 -1
- package/package.json +36 -28
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/processors/index.cjs.map +0 -1
- package/dist/processors/index.js.map +0 -1
- package/dist/processors/token-limiter.d.ts +0 -32
- package/dist/processors/token-limiter.d.ts.map +0 -1
- package/dist/processors/tool-call-filter.d.ts +0 -20
- package/dist/processors/tool-call-filter.d.ts.map +0 -1
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
3
|
+
# Agent networks
|
|
4
|
+
|
|
5
|
+
> **Deprecated:** Agent networks are deprecated and will be removed in a future major release. [Supervisor agents](https://mastra.ai/docs/capabilities/subagents) using `agent.stream()` or `agent.generate()` are now the recommended approach. It provides the same multi-agent coordination with better control, a simpler API, and easier debugging.
|
|
6
|
+
>
|
|
7
|
+
> See the [migration guide](https://mastra.ai/guides/migrations/network-to-supervisor) to upgrade.
|
|
8
|
+
|
|
9
|
+
A **routing agent** uses an LLM to interpret a request and decide which primitives (subagents, workflows, or tools) to call, in what order, and with what data.
|
|
10
|
+
|
|
11
|
+
## Create an agent network
|
|
12
|
+
|
|
13
|
+
Configure a routing agent with `agents`, `workflows`, and `tools`. Memory is required as `.network()` uses it to store task history and determine when a task is complete.
|
|
14
|
+
|
|
15
|
+
Each primitive needs a clear `description` so the routing agent can decide which to use. For workflows and tools, `inputSchema` and `outputSchema` also help the router determine the right inputs.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { Agent } from '@mastra/core/agent'
|
|
19
|
+
import { Memory } from '@mastra/memory'
|
|
20
|
+
import { LibSQLStore } from '@mastra/libsql'
|
|
21
|
+
|
|
22
|
+
import { researchAgent } from './research-agent'
|
|
23
|
+
import { writingAgent } from './writing-agent'
|
|
24
|
+
import { cityWorkflow } from '../workflows/city-workflow'
|
|
25
|
+
import { weatherTool } from '../tools/weather-tool'
|
|
26
|
+
|
|
27
|
+
export const routingAgent = new Agent({
|
|
28
|
+
id: 'routing-agent',
|
|
29
|
+
name: 'Routing Agent',
|
|
30
|
+
instructions: `
|
|
31
|
+
You are a network of writers and researchers. The user will ask you to research a topic. Always respond with a complete report—no bullet points. Write in full paragraphs, like a blog post. Do not answer with incomplete or uncertain information.`,
|
|
32
|
+
model: 'openai/gpt-5.6-sol',
|
|
33
|
+
agents: {
|
|
34
|
+
researchAgent,
|
|
35
|
+
writingAgent,
|
|
36
|
+
},
|
|
37
|
+
workflows: {
|
|
38
|
+
cityWorkflow,
|
|
39
|
+
},
|
|
40
|
+
tools: {
|
|
41
|
+
weatherTool,
|
|
42
|
+
},
|
|
43
|
+
memory: new Memory({
|
|
44
|
+
storage: new LibSQLStore({
|
|
45
|
+
id: 'mastra-storage',
|
|
46
|
+
url: 'file:../mastra.db',
|
|
47
|
+
}),
|
|
48
|
+
}),
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
> **Note:** Subagents need a `description` on the `Agent` instance. Workflows and tools need a `description` plus `inputSchema` and `outputSchema` on `createWorkflow()` or `createTool()`.
|
|
53
|
+
|
|
54
|
+
## Call the network
|
|
55
|
+
|
|
56
|
+
Call `.network()` with a user message. The method returns a stream of events you can iterate over.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const result = await routingAgent.network('Tell me three cool ways to use Mastra')
|
|
60
|
+
|
|
61
|
+
for await (const chunk of result) {
|
|
62
|
+
console.log(chunk.type)
|
|
63
|
+
if (chunk.type === 'network-execution-event-step-finish') {
|
|
64
|
+
console.log(chunk.payload.result)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Structured output
|
|
70
|
+
|
|
71
|
+
Pass `structuredOutput` to get typed, validated results. Use `objectStream` for partial objects as they generate.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { z } from 'zod'
|
|
75
|
+
|
|
76
|
+
const resultSchema = z.object({
|
|
77
|
+
summary: z.string().describe('A brief summary of the findings'),
|
|
78
|
+
recommendations: z.array(z.string()).describe('List of recommendations'),
|
|
79
|
+
confidence: z.number().min(0).max(1).describe('Confidence score'),
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const stream = await routingAgent.network('Research AI trends', {
|
|
83
|
+
structuredOutput: { schema: resultSchema },
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
for await (const partial of stream.objectStream) {
|
|
87
|
+
console.log('Building result:', partial)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const final = await stream.object
|
|
91
|
+
console.log(final?.summary)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Approve and decline tool calls
|
|
95
|
+
|
|
96
|
+
When a primitive requires approval, the stream emits an `agent-execution-approval` or `tool-execution-approval` chunk. Use `approveNetworkToolCall()` or `declineNetworkToolCall()` to respond.
|
|
97
|
+
|
|
98
|
+
Network approval uses snapshots to capture execution state. Ensure a [storage provider](https://mastra.ai/docs/storage/overview) is enabled in your Mastra instance.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const stream = await routingAgent.network('Perform some sensitive action', {
|
|
102
|
+
memory: {
|
|
103
|
+
thread: 'user-123',
|
|
104
|
+
resource: 'my-app',
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
for await (const chunk of stream) {
|
|
109
|
+
if (chunk.type === 'agent-execution-approval' || chunk.type === 'tool-execution-approval') {
|
|
110
|
+
// Approve
|
|
111
|
+
const approvedStream = await routingAgent.approveNetworkToolCall(chunk.payload.toolCallId, {
|
|
112
|
+
runId: stream.runId,
|
|
113
|
+
memory: { thread: 'user-123', resource: 'my-app' },
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
for await (const c of approvedStream) {
|
|
117
|
+
if (c.type === 'network-execution-event-step-finish') {
|
|
118
|
+
console.log(c.payload.result)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
To decline instead, call `declineNetworkToolCall()` with the same arguments.
|
|
126
|
+
|
|
127
|
+
## Suspend and resume
|
|
128
|
+
|
|
129
|
+
When a primitive calls `suspend()`, the stream emits a suspension chunk (e.g., `tool-execution-suspended`). Use `resumeNetwork()` to provide the requested data and continue execution.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const stream = await routingAgent.network('Delete the old records', {
|
|
133
|
+
memory: { thread: 'user-123', resource: 'my-app' },
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
for await (const chunk of stream) {
|
|
137
|
+
if (chunk.type === 'workflow-execution-suspended') {
|
|
138
|
+
console.log(chunk.payload.suspendPayload)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Resume with user confirmation
|
|
143
|
+
const resumedStream = await routingAgent.resumeNetwork(
|
|
144
|
+
{ confirmed: true },
|
|
145
|
+
{
|
|
146
|
+
runId: stream.runId,
|
|
147
|
+
memory: { thread: 'user-123', resource: 'my-app' },
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
for await (const chunk of resumedStream) {
|
|
152
|
+
if (chunk.type === 'network-execution-event-step-finish') {
|
|
153
|
+
console.log(chunk.payload.result)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Automatic resumption
|
|
159
|
+
|
|
160
|
+
Set `autoResumeSuspendedTools` to `true` so the network resumes suspended primitives based on the user's next message. This creates a conversational flow where users provide the required information naturally.
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
const stream = await routingAgent.network('Delete the old records', {
|
|
164
|
+
autoResumeSuspendedTools: true,
|
|
165
|
+
memory: { thread: 'user-123', resource: 'my-app' },
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Requirements for automatic resumption:
|
|
170
|
+
|
|
171
|
+
- **Memory configured**: The agent needs memory to track suspended tools across messages.
|
|
172
|
+
- **Same thread**: The follow-up message must use the same `thread` and `resource` identifiers.
|
|
173
|
+
- **`resumeSchema` defined**: The tool must define a `resumeSchema` so the network can extract data from the user's message.
|
|
174
|
+
|
|
175
|
+
| | Manual (`resumeNetwork`) | Automatic (`autoResumeSuspendedTools`) |
|
|
176
|
+
| -------- | ---------------------------------------------- | ----------------------------------------- |
|
|
177
|
+
| Best for | Custom UIs with approval buttons | Chat-style interfaces |
|
|
178
|
+
| Control | Full control over resume timing and data | Network extracts data from user's message |
|
|
179
|
+
| Setup | Handle suspension chunks, call `resumeNetwork` | Set flag, define `resumeSchema` on tools |
|
|
180
|
+
|
|
181
|
+
## Related
|
|
182
|
+
|
|
183
|
+
- [Supervisor agents](https://mastra.ai/docs/capabilities/subagents)
|
|
184
|
+
- [Migration: `.network()` to supervisor agents](https://mastra.ai/guides/migrations/network-to-supervisor)
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
3
|
+
# Subagents
|
|
4
|
+
|
|
5
|
+
**Added in:** `@mastra/core@1.8.0`
|
|
6
|
+
|
|
7
|
+
Subagents are specialized agents that another agent can delegate tasks to. Add them to the parent agent's `agents` property, then call [`Agent.stream()`](https://mastra.ai/reference/streaming/agents/stream) or [`Agent.generate()`](https://mastra.ai/reference/agents/generate). The parent agent uses its instructions and each subagent's `description` to decide when and how to delegate tasks.
|
|
8
|
+
|
|
9
|
+
## When to use subagents
|
|
10
|
+
|
|
11
|
+
Use subagents when a task requires agents with different specializations to work together. The parent agent decides when to delegate and passes context to each subagent. It then synthesizes their results.
|
|
12
|
+
|
|
13
|
+
Common use cases:
|
|
14
|
+
|
|
15
|
+
- Research and writing workflows where one agent gathers data and another produces content
|
|
16
|
+
- Multi-step tasks that need different expertise at each stage
|
|
17
|
+
- Tasks where you need fine-grained control over delegation behavior
|
|
18
|
+
|
|
19
|
+
> **Note:** A parent agent that coordinates subagents is often called a supervisor. The supervisor pattern is one approach to building multi-agent systems in Mastra. For other patterns, read the [conceptual overview](https://mastra.ai/guides/concepts/multi-agent-systems).
|
|
20
|
+
|
|
21
|
+
## Quickstart
|
|
22
|
+
|
|
23
|
+
Define subagents with clear descriptions, then add them to a parent agent:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { Agent } from '@mastra/core/agent'
|
|
27
|
+
import { Memory } from '@mastra/memory'
|
|
28
|
+
import { LibSQLStore } from '@mastra/libsql'
|
|
29
|
+
|
|
30
|
+
const researchAgent = new Agent({
|
|
31
|
+
id: 'research-agent',
|
|
32
|
+
description: 'Gathers factual information and returns bullet-point summaries.',
|
|
33
|
+
model: 'openai/gpt-5-mini',
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const writingAgent = new Agent({
|
|
37
|
+
id: 'writing-agent',
|
|
38
|
+
description: 'Transforms research into well-structured articles.',
|
|
39
|
+
model: 'openai/gpt-5-mini',
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const parentAgent = new Agent({
|
|
43
|
+
id: 'parent-agent',
|
|
44
|
+
instructions: `You coordinate research and writing using specialized agents.
|
|
45
|
+
Delegate to research-agent for facts, then writing-agent for content.`,
|
|
46
|
+
model: 'openai/gpt-5.6-sol',
|
|
47
|
+
agents: { researchAgent, writingAgent },
|
|
48
|
+
memory: new Memory({
|
|
49
|
+
storage: new LibSQLStore({ id: 'storage', url: 'file:mastra.db' }),
|
|
50
|
+
}),
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const stream = await parentAgent.stream('Research AI in education and write an article', {
|
|
54
|
+
maxSteps: 10,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
for await (const chunk of stream.textStream) {
|
|
58
|
+
process.stdout.write(chunk)
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Delegation hooks
|
|
63
|
+
|
|
64
|
+
Delegation hooks let you intercept, modify, or reject delegations as they happen. Configure them under the `delegation` option, either in the agent's `defaultOptions` or per-call.
|
|
65
|
+
|
|
66
|
+
### `onDelegationStart`
|
|
67
|
+
|
|
68
|
+
Called before the parent agent delegates to a subagent. Return an object to control the delegation:
|
|
69
|
+
|
|
70
|
+
- `proceed: true`: Allow the delegation (default behavior)
|
|
71
|
+
- `proceed: false`: Reject the delegation with a `rejectionReason`
|
|
72
|
+
- `modifiedPrompt`: Rewrite the prompt sent to the subagent
|
|
73
|
+
- `modifiedMaxSteps`: Limit the subagent's iteration count
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const stream = await parentAgent.stream('Research AI trends', {
|
|
77
|
+
maxSteps: 10,
|
|
78
|
+
delegation: {
|
|
79
|
+
onDelegationStart: async context => {
|
|
80
|
+
console.log(`Delegating to: ${context.primitiveId}`)
|
|
81
|
+
|
|
82
|
+
// Modify the prompt for a specific agent
|
|
83
|
+
if (context.primitiveId === 'research-agent') {
|
|
84
|
+
return {
|
|
85
|
+
proceed: true,
|
|
86
|
+
modifiedPrompt: `${context.prompt}\n\nFocus on 2024-2025 data.`,
|
|
87
|
+
modifiedMaxSteps: 5,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Reject delegation after too many iterations
|
|
92
|
+
if (context.iteration > 8) {
|
|
93
|
+
return {
|
|
94
|
+
proceed: false,
|
|
95
|
+
rejectionReason: 'Max iterations reached. Synthesize current findings.',
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { proceed: true }
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The `context` object includes:
|
|
106
|
+
|
|
107
|
+
| Property | Description |
|
|
108
|
+
| ---------------- | ------------------------------------------------- |
|
|
109
|
+
| `primitiveId` | The ID of the subagent being delegated to |
|
|
110
|
+
| `prompt` | The prompt the parent agent is sending |
|
|
111
|
+
| `iteration` | Current iteration number |
|
|
112
|
+
| `requestContext` | The request context the subagent run will receive |
|
|
113
|
+
|
|
114
|
+
### Request context at the delegation boundary
|
|
115
|
+
|
|
116
|
+
Each delegation receives a request context whose entries are shallowly copied from the parent run, excluding run-scoped identity keys. Setting or deleting entries during the subagent run does not affect the parent's context. Set entries on `context.requestContext` in `onDelegationStart` to pass values to the delegated run:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const stream = await parentAgent.stream('Research AI trends', {
|
|
120
|
+
maxSteps: 10,
|
|
121
|
+
delegation: {
|
|
122
|
+
onDelegationStart: async context => {
|
|
123
|
+
context.requestContext.set('audience', 'technical')
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The subagent reads these entries in its tools and dynamic configuration, such as `instructions: ({ requestContext }) => ...`. See [Request Context](https://mastra.ai/docs/server/request-context) for details. Values must be JSON-serializable to work with durable agents.
|
|
130
|
+
|
|
131
|
+
### `onDelegationComplete`
|
|
132
|
+
|
|
133
|
+
Called after a delegation finishes. Use it to inspect results or provide feedback, or alternatively stop execution:
|
|
134
|
+
|
|
135
|
+
- `context.bail()`: Stop the parent agent's loop immediately
|
|
136
|
+
- Return `{ feedback: '...' }`: Add feedback that gets saved to the parent agent's memory and is visible to subsequent iterations
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const stream = await parentAgent.stream('Research AI trends', {
|
|
140
|
+
maxSteps: 10,
|
|
141
|
+
delegation: {
|
|
142
|
+
onDelegationComplete: async context => {
|
|
143
|
+
console.log(`Completed: ${context.primitiveId}`)
|
|
144
|
+
|
|
145
|
+
// Bail on errors
|
|
146
|
+
if (context.error) {
|
|
147
|
+
context.bail()
|
|
148
|
+
return {
|
|
149
|
+
feedback: `Delegation to ${context.primitiveId} failed: ${context.error}. Try a different approach.`,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The `context` object includes:
|
|
158
|
+
|
|
159
|
+
| Property | Description |
|
|
160
|
+
| ------------- | ---------------------------------------- |
|
|
161
|
+
| `primitiveId` | The ID of the subagent that ran |
|
|
162
|
+
| `result` | The subagent's response |
|
|
163
|
+
| `error` | Error if the delegation failed |
|
|
164
|
+
| `bail()` | Function to stop the parent agent's loop |
|
|
165
|
+
|
|
166
|
+
## Message filtering
|
|
167
|
+
|
|
168
|
+
By default, subagents receive the full conversation context from the parent agent. Use `messageFilter` to control what messages are shared, for example, to remove sensitive data or limit context size.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const stream = await parentAgent.stream('Research AI trends', {
|
|
172
|
+
maxSteps: 10,
|
|
173
|
+
delegation: {
|
|
174
|
+
messageFilter: ({ messages, primitiveId, prompt }) => {
|
|
175
|
+
// Remove messages containing sensitive data
|
|
176
|
+
return messages
|
|
177
|
+
.filter(msg => {
|
|
178
|
+
const content =
|
|
179
|
+
typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)
|
|
180
|
+
return !content.includes('confidential')
|
|
181
|
+
})
|
|
182
|
+
.slice(-10) // Only pass the last 10 messages
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The callback receives `messages` (the full conversation history), `primitiveId` (the subagent ID), and `prompt` (the delegation prompt). Return the filtered array of messages.
|
|
189
|
+
|
|
190
|
+
## Subagent result context
|
|
191
|
+
|
|
192
|
+
When a subagent completes, the parent agent's model receives the subagent's text response in later iterations. Nested tool calls and subagent metadata, such as thread and resource IDs, aren't added to the parent agent's model context.
|
|
193
|
+
|
|
194
|
+
Application code and UI integrations can still inspect `subAgentToolResults` and the rest of the raw delegation result in the tool result payload.
|
|
195
|
+
|
|
196
|
+
This keeps debugging and display data available without sending nested tool arguments or outputs back into the parent agent's next model call.
|
|
197
|
+
|
|
198
|
+
Set `includeSubAgentToolResultsInModelContext` to include the full subagent result, including nested tool results and subagent metadata, in the parent agent's model context.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
await parentAgent.generate('Research AI trends', {
|
|
202
|
+
delegation: {
|
|
203
|
+
includeSubAgentToolResultsInModelContext: true,
|
|
204
|
+
},
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Iteration monitoring
|
|
209
|
+
|
|
210
|
+
`onIterationComplete` is called after each iteration of the parent agent's loop. Use it to monitor execution or guide the next iteration. You can also stop execution early.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const stream = await parentAgent.stream('Research AI trends', {
|
|
214
|
+
maxSteps: 10,
|
|
215
|
+
onIterationComplete: async context => {
|
|
216
|
+
console.log(`Iteration ${context.iteration}/${context.maxIterations}`)
|
|
217
|
+
console.log(`Finish reason: ${context.finishReason}`)
|
|
218
|
+
|
|
219
|
+
// Inject feedback to guide the agent
|
|
220
|
+
if (!context.text.includes('recommendations')) {
|
|
221
|
+
return {
|
|
222
|
+
continue: true,
|
|
223
|
+
feedback: 'Please include specific recommendations in your analysis.',
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Stop early when the response is sufficient
|
|
228
|
+
if (context.text.length > 1000 && context.finishReason === 'stop') {
|
|
229
|
+
return { continue: false }
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return { continue: true }
|
|
233
|
+
},
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Return `{ continue: true }` to keep iterating, or `{ continue: false }` to stop. Include optional `feedback` to inject guidance into the conversation. When `feedback` is combined with `continue: false`, the model may get one final turn to produce a text response incorporating the feedback, but only if the current iteration is still active (e.g., after tool calls), otherwise no extra turn is granted.
|
|
238
|
+
|
|
239
|
+
## Memory isolation
|
|
240
|
+
|
|
241
|
+
Mastra isolates subagent memory during delegation. Subagents receive the full conversation context for better decision-making, but only their specific delegation prompt and response are saved to their memory.
|
|
242
|
+
|
|
243
|
+
How it works:
|
|
244
|
+
|
|
245
|
+
1. **Full context forwarded**: When the parent agent delegates, the subagent receives all messages from the parent agent's conversation
|
|
246
|
+
2. **Scoped memory saves**: Only the delegation prompt and the subagent's response are saved to the subagent's memory
|
|
247
|
+
3. **Fresh thread per invocation**: Each delegation uses a unique thread ID, ensuring clean separation
|
|
248
|
+
|
|
249
|
+
As a result, subagents have the context they need without cluttering their memory with the parent agent's entire conversation. Visit [memory in multi-agent systems](https://mastra.ai/docs/memory/overview) for more details.
|
|
250
|
+
|
|
251
|
+
## Tool approval propagation
|
|
252
|
+
|
|
253
|
+
Tool approvals propagate through the delegation chain. When a subagent uses a tool with `requireApproval: true` or calls `suspend()`, the approval request surfaces in the parent agent's stream.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const sensitiveDataTool = createTool({
|
|
257
|
+
id: 'get-user-data',
|
|
258
|
+
requireApproval: true,
|
|
259
|
+
execute: async input => {
|
|
260
|
+
return await database.getUserData(input.userId)
|
|
261
|
+
},
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
const dataAgent = new Agent({
|
|
265
|
+
id: 'data-agent',
|
|
266
|
+
tools: { sensitiveDataTool },
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
const parentAgent = new Agent({
|
|
270
|
+
id: 'parent-agent',
|
|
271
|
+
agents: { dataAgent },
|
|
272
|
+
memory: new Memory(),
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
const stream = await parentAgent.stream('Get data for user 123')
|
|
276
|
+
|
|
277
|
+
for await (const chunk of stream.fullStream) {
|
|
278
|
+
if (chunk.type === 'tool-call-approval') {
|
|
279
|
+
console.log('Tool requires approval:', chunk.payload.toolName)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Cancellation
|
|
285
|
+
|
|
286
|
+
When you pass an `abortSignal` to the parent agent's [`stream()`](https://mastra.ai/reference/streaming/agents/stream) or [`generate()`](https://mastra.ai/reference/agents/generate) call, Mastra forwards that same signal to delegated subagents. Calling `AbortController.abort()` cancels in-flight subagent runs at their next step instead of letting them run to completion.
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
const controller = new AbortController()
|
|
290
|
+
|
|
291
|
+
const stream = await parentAgent.stream('Research AI trends', {
|
|
292
|
+
abortSignal: controller.signal,
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
// Cancel the parent agent and any in-flight subagents
|
|
296
|
+
controller.abort()
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Task completion scoring
|
|
300
|
+
|
|
301
|
+
Agents don't always produce a complete, correct output on the first try. Task completion scorers can help by validating whether the task is complete after each iteration. If validation fails, the parent agent continues iterating. Feedback from failed scorers is included in the conversation context so subagents can see what was missing.
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
import { createScorer } from '@mastra/core/evals'
|
|
305
|
+
|
|
306
|
+
const taskCompleteScorer = createScorer({
|
|
307
|
+
id: 'task-complete',
|
|
308
|
+
name: 'Task Completeness',
|
|
309
|
+
}).generateScore(async context => {
|
|
310
|
+
const text = (context.run.output || '').toString()
|
|
311
|
+
const hasAnalysis = text.includes('analysis')
|
|
312
|
+
const hasRecommendations = text.includes('recommendation')
|
|
313
|
+
return hasAnalysis && hasRecommendations ? 1 : 0
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
const stream = await parentAgent.stream('Research AI in education', {
|
|
317
|
+
maxSteps: 10,
|
|
318
|
+
isTaskComplete: {
|
|
319
|
+
scorers: [taskCompleteScorer],
|
|
320
|
+
strategy: 'all',
|
|
321
|
+
onComplete: async result => {
|
|
322
|
+
console.log('Task complete:', result.complete)
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
})
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Rubric scorer
|
|
329
|
+
|
|
330
|
+
The built-in rubric scorer lets you define what "correct" looks like as a checklist and have the agent self-evaluate and iterate until every criterion is satisfied or `maxSteps` is reached.
|
|
331
|
+
|
|
332
|
+
It works as an **LLM-as-judge** scorer. After each iteration, a separate grader model reviews the agent's output against the rubric. The loop ends when every required criterion passes. A failed criterion adds its feedback to the conversation so the agent can try again.
|
|
333
|
+
|
|
334
|
+
This is most effective for tasks with clear, verifiable success criteria. You can use it like so:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
import { Agent } from '@mastra/core/agent'
|
|
338
|
+
import { createRubricScorer } from '@mastra/evals/scorers/prebuilt'
|
|
339
|
+
|
|
340
|
+
const parentAgent = new Agent({
|
|
341
|
+
id: 'parent-agent',
|
|
342
|
+
instructions: 'You coordinate research and writing using specialized agents.',
|
|
343
|
+
model: 'openai/gpt-5.6-sol',
|
|
344
|
+
agents: { researchAgent, writingAgent },
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
const rubricScorer = createRubricScorer({
|
|
348
|
+
model: 'openai/gpt-5-mini',
|
|
349
|
+
criteria: [
|
|
350
|
+
{ description: 'The response includes an analysis section' },
|
|
351
|
+
{ description: 'The response includes concrete recommendations' },
|
|
352
|
+
],
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
const stream = await parentAgent.stream('Research AI in education', {
|
|
356
|
+
maxSteps: 10,
|
|
357
|
+
isTaskComplete: {
|
|
358
|
+
scorers: [rubricScorer],
|
|
359
|
+
strategy: 'all',
|
|
360
|
+
},
|
|
361
|
+
})
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
For full API details, see the [rubric scorer reference](https://mastra.ai/reference/evals/rubric).
|
|
365
|
+
|
|
366
|
+
## Writing effective instructions
|
|
367
|
+
|
|
368
|
+
Clear instructions are essential for effective delegation.
|
|
369
|
+
|
|
370
|
+
The parent agent's `instructions` should specify the available resources and when to use each one. They should also define coordination behavior and success criteria.
|
|
371
|
+
|
|
372
|
+
Each subagent should have a clear `description` that explains its purpose and return format, including when the parent agent should use it.
|
|
373
|
+
|
|
374
|
+
The parent agent uses these descriptions to make delegation decisions.
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
const parentAgent = new Agent({
|
|
378
|
+
id: 'parent-agent',
|
|
379
|
+
instructions: `You coordinate research and writing tasks.
|
|
380
|
+
|
|
381
|
+
Available resources:
|
|
382
|
+
- researchAgent: Gathers factual data and sources (returns bullet points)
|
|
383
|
+
- writingAgent: Transforms research into narrative content (returns full paragraphs)
|
|
384
|
+
|
|
385
|
+
Delegation strategy:
|
|
386
|
+
1. For research requests: Delegate to researchAgent first
|
|
387
|
+
2. For writing requests: Delegate to writingAgent
|
|
388
|
+
3. For complex requests: Delegate to researchAgent first, then writingAgent
|
|
389
|
+
|
|
390
|
+
Success criteria:
|
|
391
|
+
- All user questions are fully answered
|
|
392
|
+
- Response is well-formatted and complete`,
|
|
393
|
+
agents: { researchAgent, writingAgent },
|
|
394
|
+
})
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Running subagents in the background
|
|
398
|
+
|
|
399
|
+
Subagent invocations are dispatched as tool calls, so they can run as [background tasks](https://mastra.ai/docs/long-running-agents/background-tasks). This is useful when one or more delegations are long-running and you don't want them to block the parent agent's response.
|
|
400
|
+
|
|
401
|
+
Enable the [backgroundTasks manager](https://mastra.ai/reference/configuration) on the Mastra instance, then opt subagents in on the parent agent:
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
const parentAgent = new Agent({
|
|
405
|
+
id: 'parent-agent',
|
|
406
|
+
instructions: 'Coordinate research and writing using the available agents.',
|
|
407
|
+
model: 'openai/gpt-5.6-sol',
|
|
408
|
+
agents: { researchAgent, writingAgent },
|
|
409
|
+
backgroundTasks: {
|
|
410
|
+
tools: {
|
|
411
|
+
researchAgent: { enabled: true, timeoutMs: 900_000 },
|
|
412
|
+
writingAgent: { enabled: true, timeoutMs: 900_000 },
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
const stream = await parentAgent.streamUntilIdle('Research AI in education and write an article', {
|
|
418
|
+
memory: { thread: 't1', resource: 'u1' },
|
|
419
|
+
})
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Use [`streamUntilIdle()`](https://mastra.ai/reference/streaming/agents/streamUntilIdle) instead of `stream()` so the stream stays open until the subagents complete and the parent agent has had a chance to respond to their results.
|
|
423
|
+
|
|
424
|
+
If a subagent isn't listed under the parent agent's `backgroundTasks.tools` but has its own background-eligible tools, the parent agent still dispatches the subagent as a background task and inherits its config. See [Inheriting from the subagent](https://mastra.ai/docs/long-running-agents/background-tasks) for details.
|
|
425
|
+
|
|
426
|
+
## Subagent versioning
|
|
427
|
+
|
|
428
|
+
When using the [editor](https://mastra.ai/docs/editor/overview), you can control which stored version of each subagent the parent agent uses at runtime. Set version overrides on the Mastra instance or per invocation:
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
const result = await parentAgent.generate('Research and write about AI safety', {
|
|
432
|
+
versions: {
|
|
433
|
+
agents: {
|
|
434
|
+
'research-agent': { status: 'published' },
|
|
435
|
+
'writing-agent': { versionId: 'draft-456' },
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
})
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Version overrides propagate automatically through delegation. See [Subagent versioning](https://mastra.ai/reference/editor/versioning) for details on resolution order and server API usage.
|
|
442
|
+
|
|
443
|
+
## Related
|
|
444
|
+
|
|
445
|
+
- [Background tasks](https://mastra.ai/docs/long-running-agents/background-tasks)
|
|
446
|
+
- [Subagent versioning](https://mastra.ai/reference/editor/versioning)
|
|
447
|
+
- [Guide: Research coordinator](https://mastra.ai/guides/guide/research-coordinator)
|
|
448
|
+
- [Agent.stream() reference](https://mastra.ai/reference/streaming/agents/stream)
|
|
449
|
+
- [Agent.streamUntilIdle() reference](https://mastra.ai/reference/streaming/agents/streamUntilIdle)
|
|
450
|
+
- [Agent.generate() reference](https://mastra.ai/reference/agents/generate)
|
|
451
|
+
- [Agent approval](https://mastra.ai/docs/agents/agent-approval)
|
|
452
|
+
- [Memory in multi-agent systems](https://mastra.ai/docs/memory/overview)
|
|
453
|
+
- [Concept: Multi-agent systems](https://mastra.ai/guides/concepts/multi-agent-systems)
|
|
454
|
+
- 📹 [Mastra supervisor agents workshop](https://www.youtube.com/watch?v=FNb2fL9WhQg\&t=1872s)
|