@mastra/memory 1.24.0 → 1.25.0-alpha.1
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 +43 -0
- package/dist/docs/SKILL.md +6 -6
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-agents-agent-approval.md +85 -11
- package/dist/docs/references/docs-agents-networks.md +2 -2
- package/dist/docs/references/docs-agents-supervisor-agents.md +19 -13
- package/dist/docs/references/docs-evals-evals-with-memory.md +4 -4
- package/dist/docs/references/docs-long-running-agents-background-tasks.md +10 -10
- package/dist/docs/references/docs-long-running-agents-goals.md +15 -11
- package/dist/docs/references/docs-memory-memory-processors.md +10 -10
- package/dist/docs/references/docs-memory-message-history.md +11 -5
- package/dist/docs/references/docs-memory-multi-user-threads.md +6 -6
- package/dist/docs/references/docs-memory-observational-memory.md +57 -38
- package/dist/docs/references/docs-memory-overview.md +24 -10
- package/dist/docs/references/docs-memory-semantic-recall.md +3 -3
- package/dist/docs/references/docs-memory-working-memory.md +8 -8
- package/dist/docs/references/docs-storage-overview.md +2 -2
- package/dist/docs/references/reference-memory-clone-utilities.md +1 -1
- package/dist/docs/references/reference-memory-cloneThread.md +3 -3
- package/dist/docs/references/reference-memory-listThreads.md +1 -1
- package/dist/docs/references/reference-memory-memory-class.md +4 -4
- package/dist/docs/references/reference-memory-observational-memory.md +88 -38
- package/dist/docs/references/reference-memory-summarizeConversation.md +3 -3
- package/dist/docs/references/reference-memory-summarizeThread.md +3 -3
- package/dist/docs/references/reference-processors-token-limiter-processor.md +4 -4
- package/dist/docs/references/reference-storage-dsql.md +3 -3
- package/dist/docs/references/reference-storage-dynamodb.md +7 -7
- package/dist/docs/references/reference-storage-mongodb.md +2 -2
- package/dist/docs/references/reference-storage-postgresql.md +2 -2
- package/dist/docs/references/reference-storage-redis.md +1 -1
- package/dist/docs/references/reference-storage-upstash.md +1 -1
- package/dist/docs/references/reference-vectors-libsql.md +2 -2
- package/dist/docs/references/reference-vectors-mongodb.md +16 -16
- package/dist/docs/references/reference-vectors-pg.md +5 -5
- package/dist/docs/references/reference-vectors-upstash.md +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/processors/index.cjs +1 -1
- package/dist/processors/index.js +1 -1
- package/dist/processors/observational-memory/index.d.ts +1 -1
- package/dist/processors/observational-memory/index.d.ts.map +1 -1
- package/dist/processors/observational-memory/internal-request-context.d.ts +7 -0
- package/dist/processors/observational-memory/internal-request-context.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-strategies/types.d.ts +6 -0
- package/dist/processors/observational-memory/observation-strategies/types.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts +30 -1
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/processor.d.ts.map +1 -1
- package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
- package/dist/processors/observational-memory/types.d.ts +50 -6
- package/dist/processors/observational-memory/types.d.ts.map +1 -1
- package/dist/{src-VD6qMn-H.cjs → src-C3u7zaSu.cjs} +182 -32
- package/dist/{src-VD6qMn-H.cjs.map → src-C3u7zaSu.cjs.map} +1 -1
- package/dist/{src-Ci_GvBVm.js → src-DoNjfXNm.js} +182 -32
- package/dist/{src-Ci_GvBVm.js.map → src-DoNjfXNm.js.map} +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# @mastra/memory
|
|
2
2
|
|
|
3
|
+
## 1.25.0-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix schema-backed Observational Memory extractors throwing a "wrong resourceId" error during observer or reflector processing when the request context carries a resource ID. Agents configured with a schema-backed `Extractor` now run extraction passes without erroring. ([#19744](https://github.com/mastra-ai/mastra/pull/19744))
|
|
8
|
+
|
|
9
|
+
- Agents using observational memory or working-memory state signals no longer fail when invoked without a chat thread. ([#20471](https://github.com/mastra-ai/mastra/pull/20471))
|
|
10
|
+
|
|
11
|
+
Ephemeral agent invocations (workflow agent steps, sub-agent tool calls) don't have — and don't need — a persistent chat thread, but the `observational-memory` and `working-memory-state` processors previously threw "requires Mastra memory with an active resourceId and threadId" the moment they ran without one, aborting the call.
|
|
12
|
+
|
|
13
|
+
Both processors now handle the no-thread case gracefully at execution time: observational memory returns the message list unchanged when no thread context resolves, and working-memory state-signal computation skips when thread/resource identity is unavailable. A genuinely missing memory instance still errors as before, and threaded invocations behave exactly as they did. Processor discovery (`getInputProcessors` / `getOutputProcessors`) attaches both processors unconditionally, so discovery also works before the runtime memory context is populated.
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [[`4844167`](https://github.com/mastra-ai/mastra/commit/4844167cff2d5ec5004e94edd34970833040fa3f), [`5faf93f`](https://github.com/mastra-ai/mastra/commit/5faf93f03e19daea394b9e2a923f2e4f833407f2), [`80ad891`](https://github.com/mastra-ai/mastra/commit/80ad891f8cd10379aa5b5af7510c763783b2ab56), [`a1cb98d`](https://github.com/mastra-ai/mastra/commit/a1cb98d11990b560b98482292a1f34aa1a2d9092), [`598ad82`](https://github.com/mastra-ai/mastra/commit/598ad82d41c41389a686338a1d0e50b7400e1938), [`1fd6aad`](https://github.com/mastra-ai/mastra/commit/1fd6aad1ea4a9d32f65efa832307c35e981a4c0a)]:
|
|
16
|
+
- @mastra/core@1.56.0-alpha.4
|
|
17
|
+
|
|
18
|
+
## 1.25.0-alpha.0
|
|
19
|
+
|
|
20
|
+
### Minor Changes
|
|
21
|
+
|
|
22
|
+
- Added config-level `hooks` to Observational Memory so apps can track what OM's background model calls cost. Previously the `ObserveHooks` lifecycle callbacks only fired when calling `observe()` manually — the automatic pipeline (turn-driven observation and fire-and-forget async buffering) computed token `usage` and `providerMetadata` and dropped them. Hooks set on the OM config (including through `Memory`'s `observationalMemory` options) now fire for every observation and reflection cycle, with `threadId`/`resourceId`/`trigger` call context: ([#19058](https://github.com/mastra-ai/mastra/pull/19058))
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const memory = new Memory({
|
|
26
|
+
storage,
|
|
27
|
+
options: {
|
|
28
|
+
observationalMemory: {
|
|
29
|
+
hooks: {
|
|
30
|
+
onObservationEnd: ({ usage, providerMetadata, error, threadId, trigger }) => {
|
|
31
|
+
recordOmSpend({ usage, providerMetadata, threadId, trigger });
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Failed async-buffered cycles never throw (they are fire-and-forget), so they report through the end hook's `error` field instead. Errors thrown by config-level hooks are caught and logged, never failing the cycle. Per-call `observe()` hooks keep their existing payloads and semantics.
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- Updated dependencies [[`594f7b2`](https://github.com/mastra-ai/mastra/commit/594f7b28f5263fb9982fd50d95c471fb971ea984), [`311f943`](https://github.com/mastra-ai/mastra/commit/311f943bee60e8fdf5c84499ea50e884276c936c), [`0c89896`](https://github.com/mastra-ai/mastra/commit/0c8989673fb7d106837098398131e570c6023b68), [`23b4238`](https://github.com/mastra-ai/mastra/commit/23b423844ad0bcf2a502a68dd62866d6160f9f6d), [`e320a76`](https://github.com/mastra-ai/mastra/commit/e320a763feaf65c6be3cebecf746defcbde161b3), [`03b4918`](https://github.com/mastra-ai/mastra/commit/03b4918c80d188ce375334c393e131c6e94bd7eb), [`14ef73a`](https://github.com/mastra-ai/mastra/commit/14ef73a4bbd73e7808414816eb0628ce1d80b5d7), [`1d677d5`](https://github.com/mastra-ai/mastra/commit/1d677d5f99d7db403f7828585e8c25f299f72628), [`93e28ec`](https://github.com/mastra-ai/mastra/commit/93e28ecce9031c02397e0ae8406593e5c7a95883), [`729dab4`](https://github.com/mastra-ai/mastra/commit/729dab408faccfaef0cbb048e5a4338f9172847e), [`484003d`](https://github.com/mastra-ai/mastra/commit/484003d33ff59330c86b19863e4a38732d7e4155), [`933d291`](https://github.com/mastra-ai/mastra/commit/933d291146b789c19442ad206f94da3e4be90c64)]:
|
|
44
|
+
- @mastra/core@1.56.0-alpha.3
|
|
45
|
+
|
|
3
46
|
## 1.24.0
|
|
4
47
|
|
|
5
48
|
### Minor Changes
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: mastra-memory
|
|
|
3
3
|
description: Documentation for @mastra/memory. Use when working with @mastra/memory APIs, configuration, or implementation.
|
|
4
4
|
metadata:
|
|
5
5
|
package: "@mastra/memory"
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.25.0-alpha.1"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## When to use
|
|
@@ -16,11 +16,11 @@ Read the individual reference documents for detailed explanations and code examp
|
|
|
16
16
|
|
|
17
17
|
### Docs
|
|
18
18
|
|
|
19
|
-
- [Agent approval](references/docs-agents-agent-approval.md) - Learn how to require approvals
|
|
19
|
+
- [Agent approval](references/docs-agents-agent-approval.md) - Learn how to require approvals and suspend tool execution, plus automatically resume suspended tools while keeping humans in control of agent workflows.
|
|
20
20
|
- [Agent networks](references/docs-agents-networks.md) - Coordinate multiple agents, workflows, and tools using agent networks for complex, non-deterministic task execution.
|
|
21
21
|
- [Supervisor agents](references/docs-agents-supervisor-agents.md) - Learn how to coordinate multiple agents with delegation hooks, iteration monitoring, message filtering, and task completion scoring.
|
|
22
|
-
- [Evals with memory](references/docs-evals-evals-with-memory.md) - Run scorers against memory-enabled agents
|
|
23
|
-
- [Background tasks](references/docs-long-running-agents-background-tasks.md) - Learn how to dispatch long-running tool calls in the background
|
|
22
|
+
- [Evals with memory](references/docs-evals-evals-with-memory.md) - Run scorers against memory-enabled agents, including observational memory in thread scope, using runEvals and dataset experiments.
|
|
23
|
+
- [Background tasks](references/docs-long-running-agents-background-tasks.md) - Learn how to dispatch long-running tool calls in the background and keep the stream open until they complete, plus orchestrate subagents asynchronously.
|
|
24
24
|
- [Goals](references/docs-long-running-agents-goals.md) - Learn how to set a durable objective on an agent that's judged in the execution loop, so the agent keeps working until the goal is complete or the run budget is exhausted.
|
|
25
25
|
- [Memory processors](references/docs-memory-memory-processors.md) - Learn how to use memory processors in Mastra to filter, trim, and transform messages before they're sent to the language model to manage context window limits.
|
|
26
26
|
- [Message history](references/docs-memory-message-history.md) - Learn how to configure message history in Mastra to store recent messages from the current conversation.
|
|
@@ -41,8 +41,8 @@ Read the individual reference documents for detailed explanations and code examp
|
|
|
41
41
|
- [Reference: Memory.createThread()](references/reference-memory-createThread.md) - Documentation for the `Memory.createThread()` method in Mastra, which creates a new conversation thread in the memory system.
|
|
42
42
|
- [Reference: Memory.getThreadById()](references/reference-memory-getThreadById.md) - Documentation for the `Memory.getThreadById()` method in Mastra, which retrieves a specific thread by its ID.
|
|
43
43
|
- [Reference: Memory.listThreads()](references/reference-memory-listThreads.md) - Documentation for the `Memory.listThreads()` method in Mastra, which retrieves threads with optional filtering by resourceId and/or metadata.
|
|
44
|
-
- [Reference: Memory class](references/reference-memory-memory-class.md) - Documentation for the `Memory` class in Mastra, which provides a
|
|
45
|
-
- [Reference: Observational Memory](references/reference-memory-observational-memory.md) - API reference for Observational Memory in Mastra
|
|
44
|
+
- [Reference: Memory class](references/reference-memory-memory-class.md) - Documentation for the `Memory` class in Mastra, which provides a reliable system for managing conversation history and thread-based message storage.
|
|
45
|
+
- [Reference: Observational Memory](references/reference-memory-observational-memory.md) - API reference for Observational Memory in Mastra: a three-tier memory system that uses Observer and Reflector agents to maintain long-term memory across conversations.
|
|
46
46
|
- [Reference: summarizeConversation()](references/reference-memory-summarizeConversation.md) - Documentation for the standalone `summarizeConversation()` function in Mastra, which summarizes messages you pass in and extracts structured values from them.
|
|
47
47
|
- [Reference: Memory.summarizeThread()](references/reference-memory-summarizeThread.md) - Documentation for the `Memory.summarizeThread()` method in Mastra, which summarizes a thread's conversation in one shot and extracts structured values from it.
|
|
48
48
|
- [Reference: TokenLimiterProcessor](references/reference-processors-token-limiter-processor.md) - Documentation for the TokenLimiterProcessor in Mastra, which limits the number of tokens in messages.
|
|
@@ -6,7 +6,7 @@ Agents sometimes require the same [human-in-the-loop](https://mastra.ai/docs/wor
|
|
|
6
6
|
|
|
7
7
|
## When to use agent approval
|
|
8
8
|
|
|
9
|
-
- **Destructive or irreversible actions** such as deleting records
|
|
9
|
+
- **Destructive or irreversible actions** such as deleting records or sending emails, or alternatively processing payments.
|
|
10
10
|
- **Cost-heavy operations** like calling expensive third-party APIs where you want to verify arguments first.
|
|
11
11
|
- **Conditional confirmation** where a tool starts executing and then discovers it needs the user to confirm or supply extra data before finishing.
|
|
12
12
|
|
|
@@ -60,7 +60,7 @@ Mastra offers two distinct mechanisms for pausing tool calls: **pre-execution ap
|
|
|
60
60
|
|
|
61
61
|
Pre-execution approval pauses a tool call _before_ its `execute` function runs. The LLM still decides which tool to call and provides arguments, but `execute` doesn't run until you explicitly approve.
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
The flags control this, combined with OR logic. If _either_ is `true`, the call pauses:
|
|
64
64
|
|
|
65
65
|
| Flag | Where to set it | Scope |
|
|
66
66
|
| --------------------------- | --------------------------------- | ------------------------------------------- |
|
|
@@ -92,7 +92,7 @@ for await (const chunk of stream.fullStream) {
|
|
|
92
92
|
|
|
93
93
|
#### Conditional approval with a function
|
|
94
94
|
|
|
95
|
-
Instead of a boolean, `requireToolApproval` accepts a function that decides per tool call. It receives the `toolName`, the `args` the model passed, the `requestContext`, and the `workspace`. Return `true` to require approval for that call, or `false` to allow it. This lets you gate approval
|
|
95
|
+
Instead of a boolean, `requireToolApproval` accepts a function that decides per tool call. It receives the `toolName`, the `args` the model passed, the `requestContext`, and the `workspace`. Return `true` to require approval for that call, or `false` to allow it. This lets you gate approval at runtime, for example, only for tools whose name matches a pattern:
|
|
96
96
|
|
|
97
97
|
```typescript
|
|
98
98
|
const stream = await agent.stream('Clean up old records', {
|
|
@@ -100,10 +100,82 @@ const stream = await agent.stream('Clean up old records', {
|
|
|
100
100
|
})
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
A tool's own `requireApproval` setting
|
|
103
|
+
A tool's own `requireApproval` setting takes precedence over the function above. Its rule decides whether that tool needs approval. If the function throws, the call requires approval as a fail-safe.
|
|
104
104
|
|
|
105
105
|
> **Note:** Function-based `requireToolApproval` is only available on regular `stream()` / `generate()` calls. Durable agents and stored agents persist their options, and a function can't be serialized, so they accept only a boolean. If you pass a function in those contexts it falls back to requiring approval for every tool call.
|
|
106
106
|
|
|
107
|
+
#### Bind approval to the exact tool arguments
|
|
108
|
+
|
|
109
|
+
For sensitive tools, bind the approval to the exact tool name and arguments that were shown to the reviewer. If those arguments drift before execution, the tool shouldn't run under the old approval.
|
|
110
|
+
|
|
111
|
+
The `tool-call-approval` chunk already includes `toolName`, `toolCallId`, and `args`. You can fingerprint those fields when the approval request is shown. The example below uses a JSON string as the fingerprint, but in production you should use a stable hash of the tool name and arguments:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { Agent } from '@mastra/core/agent'
|
|
115
|
+
|
|
116
|
+
// For your production usecase, build a stable hash of the tool name and args
|
|
117
|
+
function actionFingerprint(toolName: string, args: unknown) {
|
|
118
|
+
const payload = JSON.stringify({ toolName, args })
|
|
119
|
+
return `fingerprint-${payload}`
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const sensitiveTools = new Set(['issue_refund', 'delete_record'])
|
|
123
|
+
const approvedFingerprints = new Set<string>()
|
|
124
|
+
|
|
125
|
+
export const approvalBoundAgent = new Agent({
|
|
126
|
+
id: 'approval-bound-agent',
|
|
127
|
+
name: 'Approval Bound Agent',
|
|
128
|
+
model: 'openai/gpt-5.6-sol',
|
|
129
|
+
tools: { issueRefundTool, deleteRecordTool },
|
|
130
|
+
hooks: {
|
|
131
|
+
beforeToolCall: ({ toolName, input }) => {
|
|
132
|
+
if (!sensitiveTools.has(toolName)) return
|
|
133
|
+
|
|
134
|
+
const fingerprint = actionFingerprint(toolName, input)
|
|
135
|
+
if (!approvedFingerprints.delete(fingerprint)) {
|
|
136
|
+
return {
|
|
137
|
+
proceed: false,
|
|
138
|
+
output: `Tool call blocked: approval did not match ${toolName} arguments.`,
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const stream = await approvalBoundAgent.stream('Refund order ord-1042', {
|
|
148
|
+
requireToolApproval: ({ toolName }) => sensitiveTools.has(toolName),
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
async function consumeApprovalStream(currentStream: typeof stream) {
|
|
152
|
+
for await (const chunk of currentStream.fullStream) {
|
|
153
|
+
if (chunk.type === 'tool-call-approval') {
|
|
154
|
+
const { toolName, toolCallId, args } = chunk.payload
|
|
155
|
+
const fingerprint = actionFingerprint(toolName, args)
|
|
156
|
+
|
|
157
|
+
// Present toolName, args, and fingerprint to your approval UI.
|
|
158
|
+
const approved = await showApprovalDialog({ toolName, args, fingerprint })
|
|
159
|
+
|
|
160
|
+
const nextStream = approved
|
|
161
|
+
? await approveReviewedToolCall(currentStream.runId, toolCallId, fingerprint)
|
|
162
|
+
: await approvalBoundAgent.declineToolCall({ runId: currentStream.runId, toolCallId })
|
|
163
|
+
|
|
164
|
+
await consumeApprovalStream(nextStream)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function approveReviewedToolCall(runId: string, toolCallId: string, fingerprint: string) {
|
|
170
|
+
approvedFingerprints.add(fingerprint)
|
|
171
|
+
return approvalBoundAgent.approveToolCall({ runId, toolCallId })
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await consumeApprovalStream(stream)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
In production, store the approved fingerprint in durable storage scoped to the user, run, tool call, and policy version. The `Set` above is intentionally small so the boundary is clear: the approval is consumed once, and only for the same canonical tool arguments that were reviewed.
|
|
178
|
+
|
|
107
179
|
### Runtime suspension with `suspend()`
|
|
108
180
|
|
|
109
181
|
A tool can also pause _during_ its `execute` function by calling `suspend()`. This is useful when the tool starts running and then discovers it needs additional user input or confirmation before it can finish.
|
|
@@ -133,7 +205,7 @@ const weatherTool = createTool({
|
|
|
133
205
|
})
|
|
134
206
|
```
|
|
135
207
|
|
|
136
|
-
> **Note:** `suspend()` doesn't throw
|
|
208
|
+
> **Note:** `suspend()` doesn't throw, return immediately after calling it (e.g. `return await suspend({ ... })`). Code after `await suspend(...)` still runs before the tool pauses.
|
|
137
209
|
|
|
138
210
|
## Tool approval with `generate()`
|
|
139
211
|
|
|
@@ -172,11 +244,11 @@ if (output.finishReason === 'suspended') {
|
|
|
172
244
|
| Decline method | `declineToolCall({ runId })` | `declineToolCallGenerate({ runId, toolCallId })` |
|
|
173
245
|
| Result | Stream to iterate | Full output object |
|
|
174
246
|
|
|
175
|
-
> **Note:** `toolCallId` is optional on all four methods. Pass it when multiple tool calls may be pending
|
|
247
|
+
> **Note:** `toolCallId` is optional on all four methods. Pass it when multiple tool calls may be pending (common in supervisor agents). When omitted, the agent resumes the most recent suspended tool call.
|
|
176
248
|
|
|
177
249
|
## Tool-level approval
|
|
178
250
|
|
|
179
|
-
Instead of pausing every tool call at the agent level, you can mark individual tools as requiring approval.
|
|
251
|
+
Instead of pausing every tool call at the agent level, you can mark individual tools as requiring approval. You get fine-grained control: only specific tools pause, while others execute immediately.
|
|
180
252
|
|
|
181
253
|
### Approval using `requireApproval`
|
|
182
254
|
|
|
@@ -303,7 +375,9 @@ const agent = new Agent({
|
|
|
303
375
|
})
|
|
304
376
|
```
|
|
305
377
|
|
|
306
|
-
When enabled, the agent detects suspended tools from message history on the next user message
|
|
378
|
+
When enabled, the agent detects suspended tools from message history on the next user message. It extracts `resumeData` based on the tool's `resumeSchema`, then automatically resumes the tool.
|
|
379
|
+
|
|
380
|
+
The following example shows a complete conversational flow:
|
|
307
381
|
|
|
308
382
|
```typescript
|
|
309
383
|
import { createTool } from '@mastra/core/tools'
|
|
@@ -386,7 +460,7 @@ Both approaches work with the same tool definitions. Automatic resumption trigge
|
|
|
386
460
|
|
|
387
461
|
## Resuming after a restart
|
|
388
462
|
|
|
389
|
-
The examples above hold on to `stream.runId` between suspension and approval. That works while the process stays alive, but in production the approval often arrives later
|
|
463
|
+
The examples above hold on to `stream.runId` between suspension and approval. That works while the process stays alive, but in production the approval often arrives later, after a page refresh, a server restart, or on a different server instance behind a load balancer.
|
|
390
464
|
|
|
391
465
|
Use [`listSuspendedRuns()`](https://mastra.ai/reference/agents/listSuspendedRuns) to rediscover the pending run for a conversation from storage:
|
|
392
466
|
|
|
@@ -414,7 +488,7 @@ if (run && toolCall) {
|
|
|
414
488
|
}
|
|
415
489
|
```
|
|
416
490
|
|
|
417
|
-
Each returned run includes the suspended tool calls (`toolCallId`, `toolName`, `args`, and `requiresApproval`). Approval suspensions (`requiresApproval: true`) are answered with `approveToolCall()` / `declineToolCall()`, while `suspend()`-based suspensions carry their `suspendPayload` and expect `resumeStream()` with resume data
|
|
491
|
+
Each returned run includes the suspended tool calls (`toolCallId`, `toolName`, `args`, and `requiresApproval`). Approval suspensions (`requiresApproval: true`) are answered with `approveToolCall()` / `declineToolCall()`, while `suspend()`-based suspensions carry their `suspendPayload` and expect `resumeStream()` with resume data, so you can rebuild the right UI for either flow without keeping any state in memory.
|
|
418
492
|
|
|
419
493
|
`sendToolApproval()` uses the same storage-backed discovery automatically: when no active run is found in memory for the thread, it looks up the suspended run in storage before failing. If several suspended runs match the thread, pass a `toolCallId` to disambiguate.
|
|
420
494
|
|
|
@@ -477,7 +551,7 @@ const supervisorAgent = new Agent({
|
|
|
477
551
|
name: 'Supervisor Agent',
|
|
478
552
|
instructions: `You coordinate data retrieval tasks.
|
|
479
553
|
Delegate to data-agent for user lookups.`,
|
|
480
|
-
model: 'openai/gpt-5.
|
|
554
|
+
model: 'openai/gpt-5.6-sol',
|
|
481
555
|
agents: { dataAgent },
|
|
482
556
|
memory: new Memory(),
|
|
483
557
|
})
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Agent networks
|
|
4
4
|
|
|
5
|
-
> **Deprecated
|
|
5
|
+
> **Deprecated:** Agent networks are deprecated and will be removed in a future major release. [Supervisor agents](https://mastra.ai/docs/agents/supervisor-agents) 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
6
|
>
|
|
7
7
|
> See the [migration guide](https://mastra.ai/guides/migrations/network-to-supervisor) to upgrade.
|
|
8
8
|
|
|
@@ -29,7 +29,7 @@ export const routingAgent = new Agent({
|
|
|
29
29
|
name: 'Routing Agent',
|
|
30
30
|
instructions: `
|
|
31
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.
|
|
32
|
+
model: 'openai/gpt-5.6-sol',
|
|
33
33
|
agents: {
|
|
34
34
|
researchAgent,
|
|
35
35
|
writingAgent,
|
|
@@ -8,7 +8,7 @@ A supervisor agent coordinates multiple subagents using [`Agent.stream()`](https
|
|
|
8
8
|
|
|
9
9
|
## When to use supervisor agents
|
|
10
10
|
|
|
11
|
-
Use supervisor agents when a task requires multiple agents with different specializations to work together. The supervisor handles delegation decisions
|
|
11
|
+
Use supervisor agents when a task requires multiple agents with different specializations to work together. The supervisor handles delegation decisions and context passing, plus result synthesis.
|
|
12
12
|
|
|
13
13
|
Common use cases:
|
|
14
14
|
|
|
@@ -43,7 +43,7 @@ const supervisor = new Agent({
|
|
|
43
43
|
id: 'supervisor',
|
|
44
44
|
instructions: `You coordinate research and writing using specialized agents.
|
|
45
45
|
Delegate to research-agent for facts, then writing-agent for content.`,
|
|
46
|
-
model: 'openai/gpt-5.
|
|
46
|
+
model: 'openai/gpt-5.6-sol',
|
|
47
47
|
agents: { researchAgent, writingAgent },
|
|
48
48
|
memory: new Memory({
|
|
49
49
|
storage: new LibSQLStore({ id: 'storage', url: 'file:mastra.db' }),
|
|
@@ -112,7 +112,7 @@ The `context` object includes:
|
|
|
112
112
|
|
|
113
113
|
### `onDelegationComplete`
|
|
114
114
|
|
|
115
|
-
Called after a delegation finishes. Use it to inspect results
|
|
115
|
+
Called after a delegation finishes. Use it to inspect results or provide feedback, or alternatively stop execution:
|
|
116
116
|
|
|
117
117
|
- `context.bail()`: Stop the supervisor loop immediately
|
|
118
118
|
- Return `{ feedback: '...' }`: Add feedback that gets saved to the supervisor's memory and is visible to subsequent iterations
|
|
@@ -147,7 +147,7 @@ The `context` object includes:
|
|
|
147
147
|
|
|
148
148
|
## Message filtering
|
|
149
149
|
|
|
150
|
-
By default, subagents receive the full conversation context from the supervisor. Use `messageFilter` to control what messages are shared
|
|
150
|
+
By default, subagents receive the full conversation context from the supervisor. Use `messageFilter` to control what messages are shared, for example, to remove sensitive data or limit context size.
|
|
151
151
|
|
|
152
152
|
```typescript
|
|
153
153
|
const stream = await supervisor.stream('Research AI trends', {
|
|
@@ -173,7 +173,9 @@ The callback receives `messages` (the full conversation history), `primitiveId`
|
|
|
173
173
|
|
|
174
174
|
When a subagent completes, the supervisor 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 supervisor model context.
|
|
175
175
|
|
|
176
|
-
Application code and UI integrations can still inspect
|
|
176
|
+
Application code and UI integrations can still inspect `subAgentToolResults` and the rest of the raw delegation result in the tool result payload.
|
|
177
|
+
|
|
178
|
+
This keeps debugging and display data available without sending nested tool arguments or outputs back into the supervisor's next model call.
|
|
177
179
|
|
|
178
180
|
Set `includeSubAgentToolResultsInModelContext` to include the full subagent result, including nested tool results and subagent metadata, in the supervisor model context.
|
|
179
181
|
|
|
@@ -187,7 +189,7 @@ await supervisor.generate('Research AI trends', {
|
|
|
187
189
|
|
|
188
190
|
## Iteration monitoring
|
|
189
191
|
|
|
190
|
-
`onIterationComplete` is called after each iteration of the supervisor loop. Use it to log progress
|
|
192
|
+
`onIterationComplete` is called after each iteration of the supervisor loop. Use it to log progress or inject feedback, or alternatively stop execution early.
|
|
191
193
|
|
|
192
194
|
```typescript
|
|
193
195
|
const stream = await supervisor.stream('Research AI trends', {
|
|
@@ -214,7 +216,7 @@ const stream = await supervisor.stream('Research AI trends', {
|
|
|
214
216
|
})
|
|
215
217
|
```
|
|
216
218
|
|
|
217
|
-
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)
|
|
219
|
+
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.
|
|
218
220
|
|
|
219
221
|
## Memory isolation
|
|
220
222
|
|
|
@@ -226,7 +228,7 @@ How it works:
|
|
|
226
228
|
2. **Scoped memory saves**: Only the delegation prompt and the subagent's response are saved to the subagent's memory
|
|
227
229
|
3. **Fresh thread per invocation**: Each delegation uses a unique thread ID, ensuring clean separation
|
|
228
230
|
|
|
229
|
-
|
|
231
|
+
As a result, subagents have the context they need without cluttering their memory with the entire supervisor conversation. Visit [memory in multi-agent systems](https://mastra.ai/docs/memory/overview) for more details.
|
|
230
232
|
|
|
231
233
|
## Tool approval propagation
|
|
232
234
|
|
|
@@ -309,7 +311,7 @@ const stream = await supervisor.stream('Research AI in education', {
|
|
|
309
311
|
|
|
310
312
|
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.
|
|
311
313
|
|
|
312
|
-
It works as an **LLM-as-judge** scorer
|
|
314
|
+
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.
|
|
313
315
|
|
|
314
316
|
This is most effective for tasks with clear, verifiable success criteria. You can use it like so:
|
|
315
317
|
|
|
@@ -320,7 +322,7 @@ import { createRubricScorer } from '@mastra/evals/scorers/prebuilt'
|
|
|
320
322
|
const supervisor = new Agent({
|
|
321
323
|
id: 'supervisor',
|
|
322
324
|
instructions: 'You coordinate research and writing using specialized agents.',
|
|
323
|
-
model: 'openai/gpt-5.
|
|
325
|
+
model: 'openai/gpt-5.6-sol',
|
|
324
326
|
agents: { researchAgent, writingAgent },
|
|
325
327
|
})
|
|
326
328
|
|
|
@@ -345,9 +347,13 @@ For full API details, see the [rubric scorer reference](https://mastra.ai/refere
|
|
|
345
347
|
|
|
346
348
|
## Writing effective instructions
|
|
347
349
|
|
|
348
|
-
Clear instructions are essential for effective delegation.
|
|
350
|
+
Clear instructions are essential for effective delegation.
|
|
351
|
+
|
|
352
|
+
Your supervisor's `instructions` should specify the available resources and when to use each one. They should also define coordination behavior and success criteria.
|
|
353
|
+
|
|
354
|
+
Each subagent should have a clear `description` that explains its purpose and return format, including when the supervisor should use it.
|
|
349
355
|
|
|
350
|
-
|
|
356
|
+
The supervisor uses these descriptions to make delegation decisions.
|
|
351
357
|
|
|
352
358
|
```typescript
|
|
353
359
|
const supervisor = new Agent({
|
|
@@ -380,7 +386,7 @@ Enable the [backgroundTasks manager](https://mastra.ai/reference/configuration)
|
|
|
380
386
|
const supervisor = new Agent({
|
|
381
387
|
id: 'supervisor',
|
|
382
388
|
instructions: 'Coordinate research and writing using the available agents.',
|
|
383
|
-
model: 'openai/gpt-5.
|
|
389
|
+
model: 'openai/gpt-5.6-sol',
|
|
384
390
|
agents: { researchAgent, writingAgent },
|
|
385
391
|
backgroundTasks: {
|
|
386
392
|
tools: {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Evals with memory
|
|
4
4
|
|
|
5
|
-
Agents that use memory in `thread` scope
|
|
5
|
+
Agents that use memory in `thread` scope, including observational memory, require a thread ID at run time. When an eval invokes the agent without one, you'll see:
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
8
|
ObservationalMemory (scope: 'thread') requires a threadId, but none was found in RequestContext or MessageList.
|
|
@@ -18,11 +18,11 @@ This page covers the three working patterns for running Mastra evals against mem
|
|
|
18
18
|
| One independent thread per item, focused CI loop | [`runEvals` per item](#per-item-threads-with-runevals) |
|
|
19
19
|
| Per-item threads driven by a stored `Dataset` | [`dataset.startExperiment` with an inline task](#dataset-experiments-with-an-inline-task) |
|
|
20
20
|
|
|
21
|
-
Pre-seeding `RequestContext` with `MastraMemory` **isn't** a supported way to drive memory into an agent. Thread resolution reads `args.memory.thread
|
|
21
|
+
Pre-seeding `RequestContext` with `MastraMemory` **isn't** a supported way to drive memory into an agent. Thread resolution reads `args.memory.thread`, `RequestContext.MastraMemory` is populated by `prepare-memory-step` after the agent has already resolved its thread.
|
|
22
22
|
|
|
23
23
|
## Shared thread with `runEvals`
|
|
24
24
|
|
|
25
|
-
`runEvals` accepts `targetOptions`, which is forwarded to `agent.generate()`. Passing `memory: { thread, resource }` runs every data item against the same thread
|
|
25
|
+
`runEvals` accepts `targetOptions`, which is forwarded to `agent.generate()`. Passing `memory: { thread, resource }` runs every data item against the same thread, useful for testing recall across a multi-turn conversation.
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
28
|
import { runEvals } from '@mastra/core/evals'
|
|
@@ -88,7 +88,7 @@ const average = scores.reduce((a, b) => a + b, 0) / scores.length
|
|
|
88
88
|
|
|
89
89
|
## Dataset experiments with an inline task
|
|
90
90
|
|
|
91
|
-
`dataset.startExperiment({ target: agent })` **doesn't** forward a `memory` option to the agent
|
|
91
|
+
`dataset.startExperiment({ target: agent })` **doesn't** forward a `memory` option to the agent, only `requestContext`. To run a stored dataset against a memory-enabled agent, use an inline `task` function and stash `{ threadId, resourceId }` in each item's `metadata`. The scorer pipeline still runs as normal.
|
|
92
92
|
|
|
93
93
|
```typescript
|
|
94
94
|
import { randomUUID } from 'node:crypto'
|
|
@@ -74,7 +74,7 @@ export const researchTool = createTool({
|
|
|
74
74
|
|
|
75
75
|
### Agent-level
|
|
76
76
|
|
|
77
|
-
Use `backgroundTasks.tools` on the agent to opt in specific tools
|
|
77
|
+
Use `backgroundTasks.tools` on the agent to opt in specific tools or override timeouts for individual tools, or alternatively run all background-eligible tools in the background. Use `disabled: true` to short-circuit background dispatch for the agent entirely.
|
|
78
78
|
|
|
79
79
|
```typescript
|
|
80
80
|
import { Agent } from '@mastra/core/agent'
|
|
@@ -82,7 +82,7 @@ import { Agent } from '@mastra/core/agent'
|
|
|
82
82
|
export const researcher = new Agent({
|
|
83
83
|
id: 'researcher',
|
|
84
84
|
instructions: 'You research topics and answer questions.',
|
|
85
|
-
model: 'openai/gpt-5.
|
|
85
|
+
model: 'openai/gpt-5.6-sol',
|
|
86
86
|
tools: { researchTool, summarizeTool },
|
|
87
87
|
backgroundTasks: {
|
|
88
88
|
tools: {
|
|
@@ -106,7 +106,7 @@ When a tool is registered on an agent that has background tasks enabled, the mod
|
|
|
106
106
|
}
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
The `_background` override is a _modifier_ on tools the developer has already opted in at the tool or agent layer
|
|
109
|
+
The `_background` override is a _modifier_ on tools the developer has already opted in at the tool or agent layer, it's not a standalone opt-in. If a tool hasn't been opted in, `_background.enabled: true` from the model is ignored and the tool runs in the foreground. This keeps deterministic, foreground-only tools (calculators, lookups, schema validators) from being silently dispatched as tasks.
|
|
110
110
|
|
|
111
111
|
### Resolution order
|
|
112
112
|
|
|
@@ -172,7 +172,7 @@ Visit [`Agent.stream()`](https://mastra.ai/reference/streaming/agents/stream) fo
|
|
|
172
172
|
|
|
173
173
|
### Aggregate properties
|
|
174
174
|
|
|
175
|
-
`stream()` with `untilIdle` returns a `MastraModelOutput` that looks like the one from a regular `stream()` call, but
|
|
175
|
+
`stream()` with `untilIdle` returns a `MastraModelOutput` that looks like the one from a regular `stream()` call, but `fullStream` alone spans the initial turn and any auto-continuations. Aggregate properties (`text`, `toolCalls`, `toolResults`, `finishReason`, `messageList`, `getFullOutput()`) still resolve against the **first turn's** internal buffer. If you need an aggregate view across continuations, consume `fullStream` yourself and accumulate.
|
|
176
176
|
|
|
177
177
|
## Subagents in the background
|
|
178
178
|
|
|
@@ -184,7 +184,7 @@ import { Agent } from '@mastra/core/agent'
|
|
|
184
184
|
const supervisor = new Agent({
|
|
185
185
|
id: 'supervisor',
|
|
186
186
|
instructions: 'Coordinate research and writing using the available agents.',
|
|
187
|
-
model: 'openai/gpt-5.
|
|
187
|
+
model: 'openai/gpt-5.6-sol',
|
|
188
188
|
agents: { researchAgent, writingAgent },
|
|
189
189
|
backgroundTasks: {
|
|
190
190
|
tools: {
|
|
@@ -260,7 +260,7 @@ export const reviewTool = createTool({
|
|
|
260
260
|
})
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
The first invocation of `execute` sees `resumeData === undefined` and calls `suspend`. After the task is resumed, the runtime restarts the tool with `resumeData` populated
|
|
263
|
+
The first invocation of `execute` sees `resumeData === undefined` and calls `suspend`. After the task is resumed, the runtime restarts the tool with `resumeData` populated. The `if` condition is false, so the tool returns its real result.
|
|
264
264
|
|
|
265
265
|
To resume the task once an approval arrives:
|
|
266
266
|
|
|
@@ -273,19 +273,19 @@ await mastra.backgroundTaskManager?.resume(taskId, {
|
|
|
273
273
|
|
|
274
274
|
### What happens to the agent loop
|
|
275
275
|
|
|
276
|
-
When a task suspends mid-`stream()` with `untilIdle`, the wrapper treats it as terminal for the current iteration and closes. To continue the agent immediately when the resume payload is in hand, call `agent.resumeStream(resumeData, { runId, toolCallId, memory, untilIdle: true })`: the resumed bg task runs to completion, its result
|
|
276
|
+
When a task suspends mid-`stream()` with `untilIdle`, the wrapper treats it as terminal for the current iteration and closes. To continue the agent immediately when the resume payload is in hand, call `agent.resumeStream(resumeData, { runId, toolCallId, memory, untilIdle: true })`: the resumed bg task runs to completion, its result is added to the message list, and the agent runs a follow-up turn, all on the same SSE connection. If you'd rather drive the resume out-of-band, call `mastra.backgroundTaskManager.resume(taskId, resumeData)` directly and the result still writes into the thread for the next user turn to pick up.
|
|
277
277
|
|
|
278
278
|
### Re-registering the executor on resume
|
|
279
279
|
|
|
280
|
-
The manager keeps tool executors in process memory. If the process restarts while a task is suspended, the executor closure is gone
|
|
280
|
+
The manager keeps tool executors in process memory. If the process restarts while a task is suspended, the executor closure is gone, the caller of `resume()` must re-register it first via `manager.registerTaskContext(taskId, ...)`. Tasks dispatched and resumed inside the same process don't need this.
|
|
281
281
|
|
|
282
282
|
### Cancelling a suspended task
|
|
283
283
|
|
|
284
|
-
`manager.cancel(taskId)` works against suspended tasks the same way it works for running ones
|
|
284
|
+
`manager.cancel(taskId)` works against suspended tasks the same way it works for running ones. The row changes to `cancelled` and the workflow snapshot is cleaned up. A `task.cancelled` event then fires.
|
|
285
285
|
|
|
286
286
|
## Lifecycle callbacks
|
|
287
287
|
|
|
288
|
-
Each layer can register terminal-state callbacks. They don't replace one another, and success/failure hooks fire for their
|
|
288
|
+
Each layer can register terminal-state callbacks. They don't replace one another, and success/failure hooks fire for their outcomes:
|
|
289
289
|
|
|
290
290
|
- Tool-level `background.onComplete` / `onFailed`: scoped to one tool.
|
|
291
291
|
- Agent-level `backgroundTasks.onTaskComplete` / `onTaskFailed`: scoped to all tasks dispatched by this agent.
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
> **Beta:** The Goals feature is in beta stage and subject to breaking changes in minor versions until it graduates from its beta status.
|
|
8
8
|
|
|
9
|
-
A goal is a durable, thread-scoped objective: a standing instruction the agent keeps working toward across loop iterations until a judge model decides it's satisfied or a run budget is exhausted.
|
|
9
|
+
A goal is a durable, thread-scoped objective: a standing instruction the agent keeps working toward across loop iterations until a judge model decides it's satisfied or a run budget is exhausted.
|
|
10
|
+
|
|
11
|
+
The objective is persisted in thread state, so it survives reloads and is evaluated in-loop, even when a new message arrives in the middle of an already-running turn.
|
|
10
12
|
|
|
11
13
|
Goals build on the same machinery as [`isTaskComplete`](https://mastra.ai/docs/agents/supervisor-agents): an LLM-as-judge scores the agent's output each iteration and gates the loop. The difference is that a goal is **durable** (stored in thread state, not passed per call) and is set and updated through `Agent` methods rather than per-`stream()` options.
|
|
12
14
|
|
|
@@ -22,7 +24,7 @@ For a one-off completion check within a single `stream()` call, use [`isTaskComp
|
|
|
22
24
|
|
|
23
25
|
## Quickstart
|
|
24
26
|
|
|
25
|
-
Goals require a configured [storage](https://mastra.ai/docs/storage/overview) backend and a memory-backed thread. Add a `goal` config to the agent
|
|
27
|
+
Goals require a configured [storage](https://mastra.ai/docs/storage/overview) backend and a memory-backed thread. Add a `goal` config to the agent, a judge model is required for the goal to do anything, then set an objective for a thread:
|
|
26
28
|
|
|
27
29
|
```typescript
|
|
28
30
|
import { Agent } from '@mastra/core/agent'
|
|
@@ -31,7 +33,7 @@ const worker = new Agent({
|
|
|
31
33
|
id: 'worker',
|
|
32
34
|
name: 'worker',
|
|
33
35
|
instructions: 'You complete software tasks end to end.',
|
|
34
|
-
model: 'openai/gpt-5.
|
|
36
|
+
model: 'openai/gpt-5.6-sol',
|
|
35
37
|
memory,
|
|
36
38
|
goal: {
|
|
37
39
|
judge: 'openai/gpt-5-mini',
|
|
@@ -51,19 +53,21 @@ const stream = await worker.stream('Start working on the goal', {
|
|
|
51
53
|
})
|
|
52
54
|
```
|
|
53
55
|
|
|
54
|
-
The `goal` config auto-registers the state-signal projection, so the model always sees the current objective as `<current-objective>` in its context
|
|
56
|
+
The `goal` config auto-registers the state-signal projection, so the model always sees the current objective as `<current-objective>` in its context without extra setup.
|
|
55
57
|
|
|
56
58
|
## How the goal step works
|
|
57
59
|
|
|
58
60
|
A goal step runs inside the agentic execution loop, right after `isTaskComplete`. On a real candidate answer it scores the conversation against the objective and gates the loop:
|
|
59
61
|
|
|
60
|
-
- **Not satisfied, budget remaining** → the loop continues
|
|
62
|
+
- **Not satisfied, budget remaining** → the loop continues. Per-evaluation feedback is injected so the agent iterates.
|
|
61
63
|
- **Satisfied** → the loop stops and the objective is marked `done`.
|
|
62
64
|
- **Budget exhausted** (`runsUsed >= maxRuns`) → the loop stops and the objective is marked `paused`. Raise `maxRuns`, then resume the objective to continue.
|
|
63
65
|
|
|
64
|
-
The step is a no-op for background-task, mid-tool-loop, and working-memory-only iterations
|
|
66
|
+
The step is a no-op for background-task, mid-tool-loop, and working-memory-only iterations, the same gating as `isTaskComplete`.
|
|
67
|
+
|
|
68
|
+
**The judge model is the activation switch.** If no judge resolves (neither the per-objective override nor the agent's `goal.judge`), the goal step performs no scoring or budget consumption and emits no `goal` chunk.
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
Effective settings resolve as per-objective record value → agent `goal` config → built-in default (`maxRuns` `50`, a default judge prompt).
|
|
67
71
|
|
|
68
72
|
By default the step uses a built-in LLM-as-judge scorer that returns `1` when the objective is achieved and `0` otherwise. Supply your own scorer with `goal.scorer` to customize judging.
|
|
69
73
|
|
|
@@ -72,7 +76,7 @@ const worker = new Agent({
|
|
|
72
76
|
id: 'worker',
|
|
73
77
|
name: 'worker',
|
|
74
78
|
instructions: 'You complete software tasks end to end.',
|
|
75
|
-
model: 'openai/gpt-5.
|
|
79
|
+
model: 'openai/gpt-5.6-sol',
|
|
76
80
|
memory,
|
|
77
81
|
goal: {
|
|
78
82
|
// A resolver function lets you inject provider credentials and read the
|
|
@@ -109,6 +113,6 @@ Per-objective values written by `setObjective` / `updateObjectiveOptions` take p
|
|
|
109
113
|
|
|
110
114
|
## Related
|
|
111
115
|
|
|
112
|
-
- [Supervisor agents](https://mastra.ai/docs/agents/supervisor-agents)
|
|
113
|
-
- [Signal providers](https://mastra.ai/docs/long-running-agents/signal-providers)
|
|
114
|
-
- [Memory storage](https://mastra.ai/docs/storage/overview)
|
|
116
|
+
- [Supervisor agents](https://mastra.ai/docs/agents/supervisor-agents): `isTaskComplete` and the rubric scorer
|
|
117
|
+
- [Signal providers](https://mastra.ai/docs/long-running-agents/signal-providers): how the objective is projected into context
|
|
118
|
+
- [Memory storage](https://mastra.ai/docs/storage/overview): the storage backend goals require
|