@mastra/mcp-docs-server 1.2.3-alpha.1 → 1.2.3-alpha.12
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/.docs/docs/agent-builder/memory.md +4 -2
- package/.docs/docs/agent-controller/overview.md +1 -1
- package/.docs/docs/agents/agent-approval.md +38 -0
- package/.docs/docs/agents/heartbeats.md +211 -0
- package/.docs/docs/agents/signals.md +25 -1
- package/.docs/docs/observability/integrations/exporters/otel.md +23 -2
- package/.docs/docs/observability/metrics/overview.md +2 -2
- package/.docs/models/gateways/openrouter.md +1 -2
- package/.docs/models/gateways/vercel.md +2 -1
- package/.docs/models/index.md +1 -1
- package/.docs/models/providers/anthropic.md +4 -5
- package/.docs/models/providers/chutes.md +17 -43
- package/.docs/models/providers/deepinfra.md +3 -2
- package/.docs/models/providers/friendli.md +1 -3
- package/.docs/models/providers/gmicloud.md +18 -15
- package/.docs/models/providers/huggingface.md +2 -1
- package/.docs/models/providers/inceptron.md +10 -8
- package/.docs/models/providers/llmgateway.md +3 -6
- package/.docs/models/providers/neuralwatt.md +9 -5
- package/.docs/models/providers/novita-ai.md +1 -1
- package/.docs/models/providers/nvidia.md +2 -1
- package/.docs/models/providers/siliconflow-cn.md +50 -78
- package/.docs/models/providers/siliconflow.md +52 -73
- package/.docs/models/providers/stepfun.md +1 -1
- package/.docs/models/providers/subconscious.md +71 -0
- package/.docs/models/providers/synthetic.md +8 -6
- package/.docs/models/providers/xiaomi.md +2 -2
- package/.docs/models/providers.md +1 -0
- package/.docs/reference/agent-controller/agent-controller-class.md +9 -9
- package/.docs/reference/agents/listSuspendedRuns.md +91 -0
- package/.docs/reference/client-js/agents.md +21 -0
- package/.docs/reference/index.md +2 -0
- package/.docs/reference/observability/metrics/automatic-metrics.md +2 -2
- package/.docs/reference/pubsub/lease-provider.md +131 -0
- package/.docs/reference/pubsub/redis-streams.md +10 -2
- package/CHANGELOG.md +43 -0
- package/package.json +5 -5
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Subconscious
|
|
2
|
+
|
|
3
|
+
Access 1 Subconscious model through Mastra's model router. Authentication is handled automatically using the `SUBCONSCIOUS_API_KEY` environment variable.
|
|
4
|
+
|
|
5
|
+
Learn more in the [Subconscious documentation](https://docs.subconscious.dev).
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
SUBCONSCIOUS_API_KEY=your-api-key
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Agent } from "@mastra/core/agent";
|
|
13
|
+
|
|
14
|
+
const agent = new Agent({
|
|
15
|
+
id: "my-agent",
|
|
16
|
+
name: "My Agent",
|
|
17
|
+
instructions: "You are a helpful assistant",
|
|
18
|
+
model: "subconscious/subconscious/tim-qwen3.6-27b"
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Generate a response
|
|
22
|
+
const response = await agent.generate("Hello!");
|
|
23
|
+
|
|
24
|
+
// Stream a response
|
|
25
|
+
const stream = await agent.stream("Tell me a story");
|
|
26
|
+
for await (const chunk of stream) {
|
|
27
|
+
console.log(chunk);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> **Info:** Mastra uses the OpenAI-compatible `/chat/completions` endpoint. Some provider-specific features may not be available. Check the [Subconscious documentation](https://docs.subconscious.dev) for details.
|
|
32
|
+
|
|
33
|
+
## Models
|
|
34
|
+
|
|
35
|
+
| Model | Context | Tools | Reasoning | Image | Audio | Video | Input $/1M | Output $/1M |
|
|
36
|
+
| ------------------------------------------- | ------- | ----- | --------- | ----- | ----- | ----- | ---------- | ----------- |
|
|
37
|
+
| `subconscious/subconscious/tim-qwen3.6-27b` | 8K | | | | | | — | — |
|
|
38
|
+
|
|
39
|
+
## Advanced configuration
|
|
40
|
+
|
|
41
|
+
### Custom headers
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const agent = new Agent({
|
|
45
|
+
id: "custom-agent",
|
|
46
|
+
name: "custom-agent",
|
|
47
|
+
model: {
|
|
48
|
+
url: "https://api.subconscious.dev/v1",
|
|
49
|
+
id: "subconscious/subconscious/tim-qwen3.6-27b",
|
|
50
|
+
apiKey: process.env.SUBCONSCIOUS_API_KEY,
|
|
51
|
+
headers: {
|
|
52
|
+
"X-Custom-Header": "value"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Dynamic model selection
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const agent = new Agent({
|
|
62
|
+
id: "dynamic-agent",
|
|
63
|
+
name: "Dynamic Agent",
|
|
64
|
+
model: ({ requestContext }) => {
|
|
65
|
+
const useAdvanced = requestContext.task === "complex";
|
|
66
|
+
return useAdvanced
|
|
67
|
+
? "subconscious/subconscious/tim-qwen3.6-27b"
|
|
68
|
+
: "subconscious/subconscious/tim-qwen3.6-27b";
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Synthetic
|
|
2
2
|
|
|
3
|
-
Access
|
|
3
|
+
Access 10 Synthetic models through Mastra's model router. Authentication is handled automatically using the `SYNTHETIC_API_KEY` environment variable.
|
|
4
4
|
|
|
5
5
|
Learn more in the [Synthetic documentation](https://synthetic.new/pricing).
|
|
6
6
|
|
|
@@ -37,11 +37,13 @@ for await (const chunk of stream) {
|
|
|
37
37
|
| `synthetic/hf:MiniMaxAI/MiniMax-M3` | 524K | | | | | | $0.60 | $1 |
|
|
38
38
|
| `synthetic/hf:moonshotai/Kimi-K2.6` | 262K | | | | | | $0.95 | $4 |
|
|
39
39
|
| `synthetic/hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4` | 262K | | | | | | $0.30 | $1 |
|
|
40
|
-
| `synthetic/hf:openai/gpt-oss-120b` |
|
|
41
|
-
| `synthetic/hf:Qwen/Qwen3.5-397B-A17B` | 262K | | | | | | $0.60 | $
|
|
42
|
-
| `synthetic/hf:
|
|
43
|
-
| `synthetic/hf:zai-org/GLM-4.7
|
|
40
|
+
| `synthetic/hf:openai/gpt-oss-120b` | 131K | | | | | | $0.10 | $0.10 |
|
|
41
|
+
| `synthetic/hf:Qwen/Qwen3.5-397B-A17B` | 262K | | | | | | $0.60 | $4 |
|
|
42
|
+
| `synthetic/hf:Qwen/Qwen3.6-27B` | 262K | | | | | | $0.45 | $4 |
|
|
43
|
+
| `synthetic/hf:zai-org/GLM-4.7` | 203K | | | | | | $0.45 | $2 |
|
|
44
|
+
| `synthetic/hf:zai-org/GLM-4.7-Flash` | 197K | | | | | | $0.10 | $0.50 |
|
|
44
45
|
| `synthetic/hf:zai-org/GLM-5.1` | 197K | | | | | | $1 | $3 |
|
|
46
|
+
| `synthetic/hf:zai-org/GLM-5.2` | 524K | | | | | | $1 | $4 |
|
|
45
47
|
|
|
46
48
|
## Advanced configuration
|
|
47
49
|
|
|
@@ -71,7 +73,7 @@ const agent = new Agent({
|
|
|
71
73
|
model: ({ requestContext }) => {
|
|
72
74
|
const useAdvanced = requestContext.task === "complex";
|
|
73
75
|
return useAdvanced
|
|
74
|
-
? "synthetic/hf:zai-org/GLM-5.
|
|
76
|
+
? "synthetic/hf:zai-org/GLM-5.2"
|
|
75
77
|
: "synthetic/hf:MiniMaxAI/MiniMax-M3";
|
|
76
78
|
}
|
|
77
79
|
});
|
|
@@ -34,8 +34,8 @@ for await (const chunk of stream) {
|
|
|
34
34
|
|
|
35
35
|
| Model | Context | Tools | Reasoning | Image | Audio | Video | Input $/1M | Output $/1M |
|
|
36
36
|
| --------------------------------- | ------- | ----- | --------- | ----- | ----- | ----- | ---------- | ----------- |
|
|
37
|
-
| `xiaomi/mimo-v2.5` | 1.0M | | | | | | $0.
|
|
38
|
-
| `xiaomi/mimo-v2.5-pro` | 1.0M | | | | | | $
|
|
37
|
+
| `xiaomi/mimo-v2.5` | 1.0M | | | | | | $0.14 | $0.28 |
|
|
38
|
+
| `xiaomi/mimo-v2.5-pro` | 1.0M | | | | | | $0.43 | $0.87 |
|
|
39
39
|
| `xiaomi/mimo-v2.5-pro-ultraspeed` | 1.0M | | | | | | $1 | $3 |
|
|
40
40
|
|
|
41
41
|
## Advanced configuration
|
|
@@ -106,6 +106,7 @@ Direct access to individual AI model providers. Each provider offers unique mode
|
|
|
106
106
|
- [STACKIT](https://mastra.ai/models/providers/stackit)
|
|
107
107
|
- [StepFun](https://mastra.ai/models/providers/stepfun)
|
|
108
108
|
- [StepFun AI](https://mastra.ai/models/providers/stepfun-ai)
|
|
109
|
+
- [Subconscious](https://mastra.ai/models/providers/subconscious)
|
|
109
110
|
- [submodel](https://mastra.ai/models/providers/submodel)
|
|
110
111
|
- [Synthetic](https://mastra.ai/models/providers/synthetic)
|
|
111
112
|
- [Tencent Coding Plan (China)](https://mastra.ai/models/providers/tencent-coding-plan)
|
|
@@ -128,7 +128,7 @@ await agentController.sendMessage({ content: 'Hello!' })
|
|
|
128
128
|
|
|
129
129
|
**disableBuiltinTools** (`BuiltinToolId[]`): Built-in tool IDs to remove from the \`controllerBuiltIn\` toolset. Valid values are \`ask\_user\`, \`submit\_plan\`, \`task\_write\`, \`task\_update\`, \`task\_complete\`, \`task\_check\`, and \`subagent\`.
|
|
130
130
|
|
|
131
|
-
**
|
|
131
|
+
**intervalHandlers** (`IntervalHandler[]`): Periodic background tasks started during \`init()\`. Use for gateway sync, cache refresh, and similar tasks.
|
|
132
132
|
|
|
133
133
|
**idGenerator** (`() => string`): Custom ID generator for AgentController-managed IDs such as threads and mode-run identifiers. (Default: `timestamp + random string`)
|
|
134
134
|
|
|
@@ -162,7 +162,7 @@ await agentController.sendMessage({ content: 'Hello!' })
|
|
|
162
162
|
|
|
163
163
|
#### `init()`
|
|
164
164
|
|
|
165
|
-
Initialize the agentController. Loads storage, initializes a static workspace (dynamic factory workspaces are resolved per-session during `createSession`), propagates memory and workspace to mode agents, and starts
|
|
165
|
+
Initialize the agentController. Loads storage, initializes a static workspace (dynamic factory workspaces are resolved per-session during `createSession`), propagates memory and workspace to mode agents, and starts interval handlers. Call this before using the agentController.
|
|
166
166
|
|
|
167
167
|
```typescript
|
|
168
168
|
await agentController.init()
|
|
@@ -220,26 +220,26 @@ const thread = await agentController.selectOrCreateThread()
|
|
|
220
220
|
|
|
221
221
|
#### `destroy()`
|
|
222
222
|
|
|
223
|
-
Stop all
|
|
223
|
+
Stop all interval handlers and clean up resources.
|
|
224
224
|
|
|
225
225
|
```typescript
|
|
226
226
|
await agentController.destroy()
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
-
#### `
|
|
229
|
+
#### `removeInterval({ id })`
|
|
230
230
|
|
|
231
|
-
Remove a specific
|
|
231
|
+
Remove a specific interval handler by ID. Calls the handler's `shutdown()` callback if defined.
|
|
232
232
|
|
|
233
233
|
```typescript
|
|
234
|
-
await agentController.
|
|
234
|
+
await agentController.removeInterval({ id: 'gateway-sync' })
|
|
235
235
|
```
|
|
236
236
|
|
|
237
|
-
#### `
|
|
237
|
+
#### `stopIntervals()`
|
|
238
238
|
|
|
239
|
-
Stop and remove all
|
|
239
|
+
Stop and remove all interval handlers.
|
|
240
240
|
|
|
241
241
|
```typescript
|
|
242
|
-
await agentController.
|
|
242
|
+
await agentController.stopIntervals()
|
|
243
243
|
```
|
|
244
244
|
|
|
245
245
|
#### `getCurrentAgent()`
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Agent.listSuspendedRuns()
|
|
2
|
+
|
|
3
|
+
**Added in:** `@mastra/core@1.43.0`
|
|
4
|
+
|
|
5
|
+
The `.listSuspendedRuns()` method lists suspended agent runs from workflow snapshot storage: runs waiting on a tool call requiring [approval](https://mastra.ai/docs/agents/agent-approval), or on a tool that called `suspend()`. Because discovery is backed by storage rather than in-memory state, it works after a server restart and across multiple server instances.
|
|
6
|
+
|
|
7
|
+
Pass the returned `runId` to [`resumeStream()`](https://mastra.ai/docs/agents/agent-approval), `approveToolCall()`, or `declineToolCall()` to continue the run.
|
|
8
|
+
|
|
9
|
+
The filter contract mirrors the workflow run listing APIs (`listWorkflowRuns`), plus the agent-level `threadId` filter.
|
|
10
|
+
|
|
11
|
+
## Usage example
|
|
12
|
+
|
|
13
|
+
Discover the pending run for a conversation and continue it. Check `requiresApproval` to pick the right continuation — `approveToolCall()` / `declineToolCall()` for approval suspensions, `resumeStream()` with resume data for `suspend()`-based suspensions:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
const { runs } = await agent.listSuspendedRuns({
|
|
17
|
+
threadId: 'thread-123',
|
|
18
|
+
resourceId: 'user-456',
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const run = runs[0]
|
|
22
|
+
const toolCall = run?.toolCalls[0]
|
|
23
|
+
|
|
24
|
+
if (run && toolCall) {
|
|
25
|
+
const stream = toolCall.requiresApproval
|
|
26
|
+
? await agent.approveToolCall({ runId: run.runId, toolCallId: toolCall.toolCallId })
|
|
27
|
+
: await agent.resumeStream({ name: 'San Francisco' }, { runId: run.runId })
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Parameters
|
|
32
|
+
|
|
33
|
+
**options** (`AgentListSuspendedRunsOptions`): Filters and pagination for scoping the results. (Default: `{}`)
|
|
34
|
+
|
|
35
|
+
**options.threadId** (`string`): Only return runs that belong to this memory thread.
|
|
36
|
+
|
|
37
|
+
**options.resourceId** (`string`): Only return runs that belong to this memory resource.
|
|
38
|
+
|
|
39
|
+
**options.fromDate** (`Date`): Only return runs created at or after this date.
|
|
40
|
+
|
|
41
|
+
**options.toDate** (`Date`): Only return runs created at or before this date.
|
|
42
|
+
|
|
43
|
+
**options.perPage** (`number`): Number of items per page. Pagination is applied when both perPage and page are provided; otherwise all matching runs are returned.
|
|
44
|
+
|
|
45
|
+
**options.page** (`number`): Zero-indexed page number.
|
|
46
|
+
|
|
47
|
+
## Returns
|
|
48
|
+
|
|
49
|
+
**result** (`Promise<AgentListSuspendedRunsResult>`): A promise that resolves to the matching runs and the total count before pagination.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
interface AgentListSuspendedRunsResult {
|
|
53
|
+
runs: AgentRun[]
|
|
54
|
+
/** Total number of matching runs, before pagination */
|
|
55
|
+
total: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface AgentRun {
|
|
59
|
+
/** Run ID accepted by resumeStream(), approveToolCall(), and declineToolCall() */
|
|
60
|
+
runId: string
|
|
61
|
+
status: 'suspended'
|
|
62
|
+
threadId?: string
|
|
63
|
+
resourceId?: string
|
|
64
|
+
/** When the run suspended */
|
|
65
|
+
suspendedAt: Date
|
|
66
|
+
/** Suspended tool calls awaiting approval or resume data */
|
|
67
|
+
toolCalls: AgentRunToolCall[]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface AgentRunToolCall {
|
|
71
|
+
toolCallId?: string
|
|
72
|
+
toolName?: string
|
|
73
|
+
/** Arguments the model supplied (approval suspensions only) */
|
|
74
|
+
args?: unknown
|
|
75
|
+
/** True when the run is waiting on a tool-call approval */
|
|
76
|
+
requiresApproval: boolean
|
|
77
|
+
/** The tool-defined suspend payload when the tool called suspend() */
|
|
78
|
+
suspendPayload?: unknown
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Discovery scope
|
|
83
|
+
|
|
84
|
+
Results are scoped to runs started by the agent you call `listSuspendedRuns()` on: snapshots persist the owning agent's id, so runs started by other agents on the same Mastra instance are not returned. In [supervisor setups](https://mastra.ai/docs/agents/agent-approval) the supervisor sees its outer run — the one to resume — while a subagent's inner run is only visible from the subagent itself. Filter by `threadId` and `resourceId` to scope results to one conversation.
|
|
85
|
+
|
|
86
|
+
Run snapshots are only persisted while a run is waiting on input and are deleted when it finishes, so suspended runs are the only runs discoverable from storage. Suspended runs only survive restarts when the Mastra instance has a persistent [storage provider](https://mastra.ai/docs/memory/storage) configured. With the default in-memory store, snapshots are lost on restart.
|
|
87
|
+
|
|
88
|
+
## Related
|
|
89
|
+
|
|
90
|
+
- [Agent approval](https://mastra.ai/docs/agents/agent-approval)
|
|
91
|
+
- [Storage](https://mastra.ai/docs/memory/storage)
|
|
@@ -362,6 +362,27 @@ response.processDataStream({
|
|
|
362
362
|
})
|
|
363
363
|
```
|
|
364
364
|
|
|
365
|
+
### `listSuspendedRuns()`
|
|
366
|
+
|
|
367
|
+
List suspended runs for the agent from storage — runs waiting on a tool-call approval or on a tool that suspended. Discovery is backed by storage, so it works after a server restart and across server instances. Pass the returned `runId` to `approveToolCall()`, `declineToolCall()`, or `resumeStream()`.
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
const { runs, total } = await agent.listSuspendedRuns({
|
|
371
|
+
threadId: 'thread-456',
|
|
372
|
+
resourceId: 'user-123',
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
if (runs[0]) {
|
|
376
|
+
console.log(runs[0].toolCalls) // [{ toolCallId, toolName, args, requiresApproval }]
|
|
377
|
+
await agent.approveToolCall({
|
|
378
|
+
runId: runs[0].runId,
|
|
379
|
+
toolCallId: runs[0].toolCalls[0].toolCallId,
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Accepts optional filters (`threadId`, `resourceId`, `fromDate`, `toDate`) and pagination (`perPage`, `page`). Returns `{ runs, total }`, where `total` is the number of matching runs before pagination. See [`Agent.listSuspendedRuns()`](https://mastra.ai/reference/agents/listSuspendedRuns) for details on the returned run shape.
|
|
385
|
+
|
|
365
386
|
### `approveToolCall()`
|
|
366
387
|
|
|
367
388
|
Approve a pending tool call and return a continuation stream. Use this when you are rendering the resumed chunks from the approval response.
|
package/.docs/reference/index.md
CHANGED
|
@@ -28,6 +28,7 @@ The Reference section provides documentation of Mastra's API, including paramete
|
|
|
28
28
|
- [.listAgents()](https://mastra.ai/reference/agents/listAgents)
|
|
29
29
|
- [.listScorers()](https://mastra.ai/reference/agents/listScorers)
|
|
30
30
|
- [.listSkills()](https://mastra.ai/reference/agents/listSkills)
|
|
31
|
+
- [.listSuspendedRuns()](https://mastra.ai/reference/agents/listSuspendedRuns)
|
|
31
32
|
- [.listTools()](https://mastra.ai/reference/agents/listTools)
|
|
32
33
|
- [.listWorkflows()](https://mastra.ai/reference/agents/listWorkflows)
|
|
33
34
|
- [.network()](https://mastra.ai/reference/agents/network)
|
|
@@ -211,6 +212,7 @@ The Reference section provides documentation of Mastra's API, including paramete
|
|
|
211
212
|
- [CachingPubSub](https://mastra.ai/reference/pubsub/caching-pubsub)
|
|
212
213
|
- [EventEmitterPubSub](https://mastra.ai/reference/pubsub/event-emitter)
|
|
213
214
|
- [GoogleCloudPubSub](https://mastra.ai/reference/pubsub/google-cloud-pubsub)
|
|
215
|
+
- [LeaseProvider](https://mastra.ai/reference/pubsub/lease-provider)
|
|
214
216
|
- [PubSub](https://mastra.ai/reference/pubsub/base)
|
|
215
217
|
- [RedisStreamsPubSub](https://mastra.ai/reference/pubsub/redis-streams)
|
|
216
218
|
- [UnixSocketPubSub](https://mastra.ai/reference/pubsub/unix-socket-pubsub)
|
|
@@ -13,7 +13,7 @@ Metrics are extracted from spans when they end. The observability layer inspects
|
|
|
13
13
|
Two conditions must be true for a metric to reach storage:
|
|
14
14
|
|
|
15
15
|
1. `MastraStorageExporter` is configured as an exporter.
|
|
16
|
-
2. The storage backend supports metrics (ClickHouse or
|
|
16
|
+
2. The storage backend supports metrics (ClickHouse, DuckDB, or Postgres v-next with the observability domain enabled).
|
|
17
17
|
|
|
18
18
|
If metrics aren't available, see [troubleshooting](#troubleshooting).
|
|
19
19
|
|
|
@@ -116,7 +116,7 @@ When you spot a spike in latency or token usage on the Metrics dashboard, correl
|
|
|
116
116
|
|
|
117
117
|
- **Observability is configured**: Verify that your `Mastra` instance has an `observability` config with at least one exporter.
|
|
118
118
|
- **`MastraStorageExporter` or `MastraPlatformExporter` is present**: Other exporters (Datadog, Langfuse, etc.) don't surface metrics in Mastra. `MastraStorageExporter` is required for the local Studio dashboard, and `MastraPlatformExporter` is required to view metrics in Mastra platform.
|
|
119
|
-
- **Storage supports metrics**: Metrics require an
|
|
119
|
+
- **Storage supports metrics**: Metrics require an analytics-capable store (ClickHouse, DuckDB, or Postgres v-next with the observability domain enabled). Other row-oriented databases (LibSQL, MSSQL) and document stores (MongoDB) aren't supported for metrics.
|
|
120
120
|
- **Sampling isn't 0%**: If sampling probability is `0` or strategy is `never`, all spans become no-ops and no metrics are extracted.
|
|
121
121
|
|
|
122
122
|
### Duration metrics are missing
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# LeaseProvider
|
|
2
|
+
|
|
3
|
+
`LeaseProvider` is the distributed leasing contract, separate from event delivery ([`PubSub`](https://mastra.ai/reference/pubsub/base)). Mastra's [signals layer](https://mastra.ai/docs/agents/signals) uses it to elect a single owner across multiple processes (for example, serverless invocations) for a given resource, most commonly a thread key. The owner is the process that wakes and runs the agent stream, so other processes route follow-up work to it instead of starting a competing run.
|
|
4
|
+
|
|
5
|
+
Leasing is a distinct concern from pub/sub. A backend implements `LeaseProvider` only when it can genuinely coordinate a lock, such as Redis via atomic `SET`/Lua, or an in-memory map for single-process. Backends that cannot lease omit it; the signals runtime feature-detects the capability and falls back to a no-op provider, preserving single-process behavior.
|
|
6
|
+
|
|
7
|
+
The built-in [`RedisStreamsPubSub`](https://mastra.ai/reference/pubsub/redis-streams) implements `LeaseProvider`, which is what enables signals to coordinate across instances in distributed and serverless deployments.
|
|
8
|
+
|
|
9
|
+
## Usage example
|
|
10
|
+
|
|
11
|
+
You don't construct a `LeaseProvider` directly. Configure a pub/sub backend that implements it (such as `RedisStreamsPubSub`) on the `Mastra` constructor, and the signals runtime uses it automatically for cross-process coordination.
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Mastra } from '@mastra/core'
|
|
15
|
+
import { RedisStreamsPubSub } from '@mastra/redis-streams'
|
|
16
|
+
|
|
17
|
+
export const mastra = new Mastra({
|
|
18
|
+
// RedisStreamsPubSub implements both PubSub and LeaseProvider
|
|
19
|
+
pubsub: new RedisStreamsPubSub({
|
|
20
|
+
url: process.env.REDIS_URL,
|
|
21
|
+
}),
|
|
22
|
+
})
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To implement leasing in a custom backend, implement the methods below. The signals runtime detects the capability structurally (so it works across package boundaries) and only uses it when all methods are present.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { PubSub } from '@mastra/core/events'
|
|
29
|
+
import type { LeaseProvider } from '@mastra/core/events'
|
|
30
|
+
|
|
31
|
+
export class CustomPubSub extends PubSub implements LeaseProvider {
|
|
32
|
+
async acquireLease(key: string, owner: string, ttlMs: number) {
|
|
33
|
+
// Atomically claim the lease, or report the current holder.
|
|
34
|
+
return { acquired: true, owner }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ...getLeaseOwner, releaseLease, renewLease, transferLease
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Methods
|
|
42
|
+
|
|
43
|
+
### Leasing
|
|
44
|
+
|
|
45
|
+
#### `acquireLease(key, owner, ttlMs)`
|
|
46
|
+
|
|
47
|
+
Atomically tries to acquire a lease on a key. Returns `{ acquired: true, owner }` if the caller claimed the lease, or `{ acquired: false, owner }` where `owner` is the current holder, so the caller can route follow-up work to them. The same owner can call `acquireLease` idempotently to renew or re-claim.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const result = await pubsub.acquireLease('thread:abc', runId, 15000)
|
|
51
|
+
|
|
52
|
+
if (result.acquired) {
|
|
53
|
+
// This process owns the thread, so wake and run the agent.
|
|
54
|
+
} else {
|
|
55
|
+
// result.owner holds the lease, so route the signal to them.
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Returns: `Promise<{ acquired: boolean; owner?: string }>`
|
|
60
|
+
|
|
61
|
+
**key** (`string`): The lease key, such as a thread key.
|
|
62
|
+
|
|
63
|
+
**owner** (`string`): Identifier for the owner, such as a \`runId\`. The same owner can call \`acquireLease\` idempotently to renew or release.
|
|
64
|
+
|
|
65
|
+
**ttlMs** (`number`): Time-to-live in milliseconds for the lease.
|
|
66
|
+
|
|
67
|
+
#### `getLeaseOwner(key)`
|
|
68
|
+
|
|
69
|
+
Reads the current owner of a lease, or `undefined` if no lease is held.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const owner = await pubsub.getLeaseOwner('thread:abc')
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Returns: `Promise<string | undefined>`
|
|
76
|
+
|
|
77
|
+
#### `releaseLease(key, owner)`
|
|
78
|
+
|
|
79
|
+
Releases a lease. This is a no-op if the caller is not the current owner: implementations check ownership atomically before releasing, so a concurrent renewal by another owner is never clobbered.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
await pubsub.releaseLease('thread:abc', runId)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Returns: `Promise<void>`
|
|
86
|
+
|
|
87
|
+
#### `renewLease(key, owner, ttlMs)`
|
|
88
|
+
|
|
89
|
+
Renews an existing lease owned by `owner`, extending its TTL. Returns `true` if the renewal succeeded and the caller still owns the lease, or `false` if the lease was lost (TTL expired or another owner took it).
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const stillOwned = await pubsub.renewLease('thread:abc', runId, 15000)
|
|
93
|
+
|
|
94
|
+
if (!stillOwned) {
|
|
95
|
+
// Lost the lease, so stop renewing and let the new owner take over.
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Returns: `Promise<boolean>`
|
|
100
|
+
|
|
101
|
+
#### `transferLease(key, fromOwner, toOwner, ttlMs)`
|
|
102
|
+
|
|
103
|
+
Atomically hands a held lease from `fromOwner` to `toOwner`, refreshing its TTL, without releasing the key in between. This is the gap-free primitive used when one owner finishes but a follow-up owner must take over the same key immediately, for example when a thread run completes and a queued follow-up run drains on the same thread. A naive release-then-acquire would briefly leave the key empty, letting a racing process win the freed lease and start a competing run.
|
|
104
|
+
|
|
105
|
+
Returns `true` if `fromOwner` still held the lease and ownership moved to `toOwner`, or `false` if the lease was already lost, in which case the caller should fall back to a fresh `acquireLease`.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const transferred = await pubsub.transferLease('thread:abc', currentRunId, nextRunId, 15000)
|
|
109
|
+
|
|
110
|
+
if (!transferred) {
|
|
111
|
+
// Lease was lost, so acquire fresh instead.
|
|
112
|
+
await pubsub.acquireLease('thread:abc', nextRunId, 15000)
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Returns: `Promise<boolean>`
|
|
117
|
+
|
|
118
|
+
> **Warning:** Backends that cannot perform the transfer atomically must still implement it as a best-effort `releaseLease(fromOwner)` followed by `acquireLease(toOwner)`, and document that the swap is non-atomic, since a racing process can win the key in the gap. Keeping the method required means callers have a single code path and atomicity is an explicit per-backend decision.
|
|
119
|
+
|
|
120
|
+
## Capability detection
|
|
121
|
+
|
|
122
|
+
The signals runtime detects `LeaseProvider` structurally rather than with `instanceof`, so detection works even when a separately published backend resolves a different copy of `@mastra/core`. A value is treated as a `LeaseProvider` when it exposes all five methods (`acquireLease`, `getLeaseOwner`, `releaseLease`, `renewLease`, `transferLease`).
|
|
123
|
+
|
|
124
|
+
When the configured pub/sub backend does not implement `LeaseProvider`, the runtime falls back to an always-win no-op provider. Every caller wins its own lease race, and release, renew, and transfer are inert, which preserves the expected single-process behavior.
|
|
125
|
+
|
|
126
|
+
## Related
|
|
127
|
+
|
|
128
|
+
- [PubSub](https://mastra.ai/reference/pubsub/base): The event delivery contract, separate from leasing
|
|
129
|
+
- [RedisStreamsPubSub](https://mastra.ai/reference/pubsub/redis-streams): The built-in backend that implements `LeaseProvider`
|
|
130
|
+
- [Signals](https://mastra.ai/docs/agents/signals): The runtime that uses leasing to coordinate thread runs across processes
|
|
131
|
+
- [Channels](https://mastra.ai/docs/agents/channels): Uses leasing to coordinate agent runs in serverless and multi-instance deployments
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# RedisStreamsPubSub
|
|
2
2
|
|
|
3
|
-
`RedisStreamsPubSub` is a [`PubSub`](https://mastra.ai/reference/pubsub/base) implementation backed by [Redis Streams](https://redis.io/docs/latest/develop/data-types/streams/). It delivers events across processes and hosts, with persistence, consumer groups, and redelivery on failure.
|
|
3
|
+
`RedisStreamsPubSub` is a [`PubSub`](https://mastra.ai/reference/pubsub/base) implementation backed by [Redis Streams](https://redis.io/docs/latest/develop/data-types/streams/). It delivers events across processes and hosts, with persistence, consumer groups, and redelivery on failure. It also implements [`LeaseProvider`](https://mastra.ai/reference/pubsub/lease-provider), so the signals layer can elect a single owner per resource across instances, which is what lets signals coordinate runs in distributed and serverless deployments.
|
|
4
4
|
|
|
5
5
|
Use it for distributed deployments where several services share an event stream. For single-process delivery, use [`EventEmitterPubSub`](https://mastra.ai/reference/pubsub/event-emitter). For Google Cloud, use [`GoogleCloudPubSub`](https://mastra.ai/reference/pubsub/google-cloud-pubsub).
|
|
6
6
|
|
|
@@ -105,4 +105,12 @@ await pubsub.close()
|
|
|
105
105
|
|
|
106
106
|
## Redelivery and reclaim
|
|
107
107
|
|
|
108
|
-
When a subscriber calls `nack`, the event is republished with an incremented `deliveryAttempt` and the original is acknowledged. Once an event reaches `maxDeliveryAttempts`, it's dropped instead of redelivered. Separately, each subscription periodically reclaims events that an earlier consumer in the group read but never acknowledged, controlled by `reclaimIntervalMs` and `reclaimIdleMs`.
|
|
108
|
+
When a subscriber calls `nack`, the event is republished with an incremented `deliveryAttempt` and the original is acknowledged. Once an event reaches `maxDeliveryAttempts`, it's dropped instead of redelivered. Separately, each subscription periodically reclaims events that an earlier consumer in the group read but never acknowledged, controlled by `reclaimIntervalMs` and `reclaimIdleMs`.
|
|
109
|
+
|
|
110
|
+
## Distributed leasing
|
|
111
|
+
|
|
112
|
+
`RedisStreamsPubSub` implements the [`LeaseProvider`](https://mastra.ai/reference/pubsub/lease-provider) contract on top of the same Redis connection. The [signals runtime](https://mastra.ai/docs/agents/signals) uses it to elect a single owner (usually per thread key) so that across instances only one process wakes and runs the agent, and others route follow-up work to the holder. This is what makes signals work on serverless and multi-instance deployments; without a shared lease, each instance would start its own competing run.
|
|
113
|
+
|
|
114
|
+
Lease keys are namespaced under the same `keyPrefix` as topics, as `<keyPrefix>:lease:<key>`. All operations are atomic: `acquireLease` uses `SET NX PX` and refreshes its own TTL idempotently, while `releaseLease`, `renewLease`, and `transferLease` use Lua scripts that check ownership before mutating, so a concurrent renewal from another owner is never clobbered.
|
|
115
|
+
|
|
116
|
+
You don't call these methods directly. Configuring `RedisStreamsPubSub` as the `pubsub` backend is enough for the runtime to detect and use the capability. See [`LeaseProvider`](https://mastra.ai/reference/pubsub/lease-provider) for the full method contract.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# @mastra/mcp-docs-server
|
|
2
2
|
|
|
3
|
+
## 1.2.3-alpha.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`b33c77d`](https://github.com/mastra-ai/mastra/commit/b33c77d5293f14a794f3ec38dc947a6676de2764), [`1009f77`](https://github.com/mastra-ai/mastra/commit/1009f772aa40016b49267c8566d0c29f6a16aa3c), [`23c31de`](https://github.com/mastra-ai/mastra/commit/23c31de96ed8153402dcf092ac84b27a0c3638c1), [`0368766`](https://github.com/mastra-ai/mastra/commit/0368766744c7ea3df4d6059e2cc15f7bdf55f5a6), [`65a66db`](https://github.com/mastra-ai/mastra/commit/65a66dbe249a0d92d828c605b955e73a983cf3b0), [`2866f04`](https://github.com/mastra-ai/mastra/commit/2866f04953edb78c1637fa45cc53abe24122edcb)]:
|
|
8
|
+
- @mastra/core@1.48.0-alpha.6
|
|
9
|
+
- @mastra/mcp@1.12.1-alpha.0
|
|
10
|
+
|
|
11
|
+
## 1.2.3-alpha.10
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [[`1917c53`](https://github.com/mastra-ai/mastra/commit/1917c53b19dac43926f29c496893b0686462dca4), [`58e287b`](https://github.com/mastra-ai/mastra/commit/58e287b1edaf978b13745a1795989cad3826e82b)]:
|
|
16
|
+
- @mastra/core@1.48.0-alpha.5
|
|
17
|
+
|
|
18
|
+
## 1.2.3-alpha.8
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [[`705ba98`](https://github.com/mastra-ai/mastra/commit/705ba98726d388a596e896225f237907ca6807a9), [`e62c108`](https://github.com/mastra-ai/mastra/commit/e62c108409dfd6a6cac0a48ec39c5cc81d24fd52), [`bfbbb01`](https://github.com/mastra-ai/mastra/commit/bfbbb01bd845ba54cdc0c678c277d08a7cb847e4)]:
|
|
23
|
+
- @mastra/core@1.48.0-alpha.4
|
|
24
|
+
|
|
25
|
+
## 1.2.3-alpha.7
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [[`cdd5f93`](https://github.com/mastra-ai/mastra/commit/cdd5f939cefa67390629704dce92563ccbf492b2), [`1b8728a`](https://github.com/mastra-ai/mastra/commit/1b8728a57fd844205a452b0b4216d20ff60c784a), [`213feb8`](https://github.com/mastra-ai/mastra/commit/213feb87bfdd1d8ec00ea660e218f9bcfcb34e7b)]:
|
|
30
|
+
- @mastra/core@1.48.0-alpha.3
|
|
31
|
+
|
|
32
|
+
## 1.2.3-alpha.5
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies [[`e420b3c`](https://github.com/mastra-ai/mastra/commit/e420b3c3ffc98bbc5b791897ea390bb47af99696)]:
|
|
37
|
+
- @mastra/core@1.48.0-alpha.2
|
|
38
|
+
|
|
39
|
+
## 1.2.3-alpha.2
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- Updated dependencies [[`95857bc`](https://github.com/mastra-ai/mastra/commit/95857bcd6669da7193f503e803f0d72a2bd66be6), [`8e9c0fb`](https://github.com/mastra-ai/mastra/commit/8e9c0fb48fd58da2efcdff2cf1202ee41092c315)]:
|
|
44
|
+
- @mastra/core@1.48.0-alpha.1
|
|
45
|
+
|
|
3
46
|
## 1.2.3-alpha.0
|
|
4
47
|
|
|
5
48
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/mcp-docs-server",
|
|
3
|
-
"version": "1.2.3-alpha.
|
|
3
|
+
"version": "1.2.3-alpha.12",
|
|
4
4
|
"description": "MCP server for accessing Mastra.ai documentation, changelogs, and news.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"jsdom": "^26.1.0",
|
|
29
29
|
"local-pkg": "^1.1.2",
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
|
-
"@mastra/mcp": "^1.12.0",
|
|
32
|
-
"@mastra/core": "1.48.0-alpha.
|
|
31
|
+
"@mastra/mcp": "^1.12.1-alpha.0",
|
|
32
|
+
"@mastra/core": "1.48.0-alpha.6"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@hono/node-server": "^1.19.11",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"tsx": "^4.22.4",
|
|
46
46
|
"typescript": "^6.0.3",
|
|
47
47
|
"vitest": "4.1.8",
|
|
48
|
-
"@internal/types-builder": "0.0.84",
|
|
49
48
|
"@internal/lint": "0.0.109",
|
|
50
|
-
"@
|
|
49
|
+
"@internal/types-builder": "0.0.84",
|
|
50
|
+
"@mastra/core": "1.48.0-alpha.6"
|
|
51
51
|
},
|
|
52
52
|
"homepage": "https://mastra.ai",
|
|
53
53
|
"repository": {
|