@mastra/mcp-docs-server 1.2.16 → 1.2.17-alpha.3
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/agents/code-mode.md +2 -2
- package/.docs/docs/agents/skills.md +1 -1
- package/.docs/docs/agents/using-tools.md +1 -1
- package/.docs/docs/harness/agent-controller.md +1 -1
- package/.docs/docs/mcp/overview.md +4 -5
- package/.docs/docs/studio/overview.md +1 -1
- package/.docs/docs/workspace/filesystem.md +182 -153
- package/.docs/docs/workspace/lsp.md +4 -5
- package/.docs/docs/workspace/sandbox.md +234 -141
- package/.docs/docs/workspace/search.md +52 -4
- package/.docs/docs/workspace/skills.md +62 -33
- package/.docs/integrations/browsers/browser-viewer.md +2 -2
- package/.docs/integrations/file-storage/amazon-s3.md +1 -1
- package/.docs/integrations/file-storage/azure-blob.md +1 -1
- package/.docs/integrations/file-storage/google-cloud-storage.md +1 -1
- package/.docs/integrations/file-storage/mesa.md +1 -1
- package/.docs/integrations/file-storage/vercel-files.md +1 -1
- package/.docs/integrations/sandboxes/apple-container.md +1 -1
- package/.docs/integrations/sandboxes/daytona.md +1 -1
- package/.docs/integrations/sandboxes/docker.md +1 -1
- package/.docs/integrations/sandboxes/e2b.md +1 -1
- package/.docs/integrations/sandboxes/modal.md +1 -1
- package/.docs/models/environment-variables.md +1 -0
- package/.docs/models/gateways/vercel.md +3 -2
- package/.docs/models/index.md +1 -1
- package/.docs/models/providers/baseten.md +2 -1
- package/.docs/models/providers/crossmodel.md +2 -2
- package/.docs/models/providers/crusoe.md +80 -0
- package/.docs/models/providers/deepinfra.md +3 -1
- package/.docs/models/providers/fireworks-ai.md +26 -20
- package/.docs/models/providers/huggingface.md +5 -1
- package/.docs/models/providers/hyper.md +1 -1
- package/.docs/models/providers/kilo.md +4 -4
- package/.docs/models/providers/llmgateway.md +3 -2
- package/.docs/models/providers/merge-gateway.md +5 -2
- package/.docs/models/providers/nano-gpt.md +6 -6
- package/.docs/models/providers/ofox.md +5 -1
- package/.docs/models/providers/opencode-go.md +2 -1
- package/.docs/models/providers/opencode.md +3 -1
- package/.docs/models/providers/requesty.md +3 -1
- package/.docs/models/providers/zai-coding-plan.md +3 -2
- package/.docs/models/providers/zhipuai-coding-plan.md +2 -1
- package/.docs/models/providers.md +1 -0
- package/.docs/reference/agent-controller/agent-controller-class.md +26 -1
- package/.docs/reference/browser/browser-viewer.md +1 -1
- package/.docs/reference/configuration.md +1 -1
- package/.docs/reference/core/removeWorkspace.md +1 -1
- package/.docs/reference/file-based-agents/workspace.md +3 -3
- package/.docs/reference/observability/tracing/exporters/mastra-platform-exporter.md +2 -0
- package/.docs/reference/processors/skill-search-processor.md +1 -1
- package/.docs/reference/tools/create-code-mode.md +1 -1
- package/.docs/reference/tools/create-tool.md +11 -3
- package/.docs/reference/tools/mcp-server.md +4 -1
- package/.docs/reference/workspace/local-filesystem.md +1 -1
- package/.docs/reference/workspace/local-sandbox.md +1 -1
- package/.docs/reference/workspace/workspace-class.md +52 -15
- package/CHANGELOG.md +14 -0
- package/package.json +5 -5
- package/.docs/docs/workspace/overview.md +0 -416
|
@@ -2,187 +2,228 @@
|
|
|
2
2
|
|
|
3
3
|
# Sandbox
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Sandboxes give Mastra agents an environment for running commands and working with files. Agents can also start background processes when the selected backend supports process management; otherwise, background-process tools are unavailable.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
In Mastra, you attach a sandbox backend to a `Workspace`. You can use one sandbox for an application or agent, or resolve separate environments for each user, tenant, or thread.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Supported backends can FUSE-mount filesystems into the sandbox, letting you seed ephemeral environments with files and persist their output between runs.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- **Background processes**: Spawn long-running processes like dev servers and watchers
|
|
13
|
-
- **Working directory**: Commands run from a specific directory
|
|
14
|
-
- **Environment variables**: Control what variables are available
|
|
15
|
-
- **Timeouts**: Prevent long-running commands from hanging
|
|
16
|
-
- **Isolation**: Optional OS-level sandboxing for security
|
|
11
|
+
## When to use sandboxes?
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
Sandboxes are useful for:
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
- **Coding agents and software factories**: Clone repositories and run shell, Git, build, or test workflows without giving autonomous agents access to the host system.
|
|
16
|
+
- **Deep research and analysis**: Use specialized libraries to process downloaded PDFs or presentations and produce new artifacts.
|
|
17
|
+
- **Long-running and parallel tasks**: Run work in separate environments without tying it to one request or sharing files and processes.
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
- [Apple Container](https://mastra.ai/integrations/sandboxes/apple-container)
|
|
24
|
-
- [Blaxel](https://mastra.ai/integrations/sandboxes/blaxel)
|
|
25
|
-
- [Daytona](https://mastra.ai/integrations/sandboxes/daytona)
|
|
26
|
-
- [Docker](https://mastra.ai/integrations/sandboxes/docker)
|
|
27
|
-
- [E2B](https://mastra.ai/integrations/sandboxes/e2b)
|
|
28
|
-
- [LocalSandbox](https://mastra.ai/reference/workspace/local-sandbox)
|
|
29
|
-
- [Mastra](https://mastra.ai/reference/workspace/platform-sandbox)
|
|
30
|
-
- [Modal](https://mastra.ai/integrations/sandboxes/modal)
|
|
31
|
-
- [Railway](https://mastra.ai/integrations/sandboxes/railway)
|
|
32
|
-
- [Vercel](https://mastra.ai/integrations/sandboxes/vercel)
|
|
19
|
+
## Quickstart
|
|
33
20
|
|
|
34
|
-
|
|
21
|
+
In Mastra, a sandbox operates through a `Workspace`. Its `sandbox` backend defines where commands run.
|
|
35
22
|
|
|
36
|
-
Create
|
|
23
|
+
Create an agent with a workspace and sandbox:
|
|
37
24
|
|
|
38
25
|
```typescript
|
|
39
26
|
import { Agent } from '@mastra/core/agent'
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
const workspace = new Workspace({
|
|
43
|
-
filesystem: new LocalFilesystem({
|
|
44
|
-
basePath: './workspace',
|
|
45
|
-
}),
|
|
46
|
-
sandbox: new LocalSandbox({
|
|
47
|
-
workingDirectory: './workspace',
|
|
48
|
-
}),
|
|
49
|
-
})
|
|
27
|
+
import { LocalSandbox, Workspace } from '@mastra/core/workspace'
|
|
50
28
|
|
|
51
|
-
const
|
|
52
|
-
id: '
|
|
29
|
+
export const codingAgent = new Agent({
|
|
30
|
+
id: 'coding-agent',
|
|
31
|
+
name: 'Coding agent',
|
|
32
|
+
instructions: 'Use the sandbox to complete coding tasks.',
|
|
53
33
|
model: 'openai/gpt-5.6-sol',
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
workspace: new Workspace({
|
|
35
|
+
sandbox: new LocalSandbox({
|
|
36
|
+
workingDirectory: './workspace',
|
|
37
|
+
}),
|
|
38
|
+
}),
|
|
56
39
|
})
|
|
57
40
|
|
|
58
|
-
|
|
59
|
-
const response = await agent.generate('Run `ls -la` in the workspace directory')
|
|
41
|
+
await codingAgent.generate('List the files in the workspace directory')
|
|
60
42
|
```
|
|
61
43
|
|
|
62
|
-
|
|
44
|
+
> **Warning:** `LocalSandbox` is the quickest sandbox to set up, but commands run on the host by default. Enable [native isolation](#localsandbox) whenever possible. For applications exposed to untrusted users, use a remote or container backend with a stronger isolation boundary instead.
|
|
63
45
|
|
|
64
|
-
|
|
46
|
+
To use a different sandbox for each user, tenant, or thread, configure a [sandbox resolver](#multi-tenant-sandboxes) instead.
|
|
65
47
|
|
|
66
|
-
|
|
48
|
+
## Using the sandbox
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
import { Agent } from '@mastra/core/agent'
|
|
70
|
-
import { Workspace, LocalSandbox } from '@mastra/core/workspace'
|
|
50
|
+
Agents receive tools for the capabilities supported by the sandbox backend:
|
|
71
51
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
})
|
|
52
|
+
| Tool | Does |
|
|
53
|
+
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
54
|
+
| `execute_command` | Runs a shell command and returns stdout, stderr, and the exit code. Supports `background: true` when the backend can spawn long-running processes. |
|
|
55
|
+
| `get_process_output` | Gets stdout, stderr, and status for a background process. Supports `tail` to limit output and `wait: true` to wait for the process to exit. This tool and `kill_process` are only added when the backend supports background processes. |
|
|
56
|
+
| `kill_process` | Stops a background process and returns its recent output. |
|
|
57
|
+
|
|
58
|
+
You can disable or rename each tool and require approval before it runs. You can also limit how much output it adds to the model's context. See the [workspace tool configuration reference](https://mastra.ai/reference/workspace/workspace-class).
|
|
80
59
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
60
|
+
Authored runtime functions, including tools and workflow steps, can get the live sandbox from their execution context. Start a server, watcher, notebook kernel, browser, or worker and interact with it across agent turns.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import type { ProcessHandle } from '@mastra/core/sandbox'
|
|
64
|
+
import { createTool } from '@mastra/core/tools'
|
|
65
|
+
import { z } from 'zod'
|
|
66
|
+
|
|
67
|
+
export const startServerTool = createTool({
|
|
68
|
+
id: 'start-server',
|
|
69
|
+
description: 'Starts a server in the sandbox',
|
|
70
|
+
inputSchema: z.object({
|
|
71
|
+
command: z.string(),
|
|
72
|
+
}),
|
|
73
|
+
execute: async ({ command }, ctx) => {
|
|
74
|
+
const sandbox = await ctx.getSandbox()
|
|
75
|
+
const server: ProcessHandle = await sandbox.spawn({ command })
|
|
76
|
+
return { pid: server.pid }
|
|
77
|
+
},
|
|
85
78
|
})
|
|
86
79
|
```
|
|
87
80
|
|
|
88
|
-
|
|
81
|
+
The authored function itself runs in your application process. Only operations called through the sandbox handle run inside the sandbox.
|
|
89
82
|
|
|
90
|
-
|
|
91
|
-
import { RequestContext } from '@mastra/core/request-context'
|
|
83
|
+
## Supported backends
|
|
92
84
|
|
|
93
|
-
|
|
94
|
-
const aliceCtx = new RequestContext([['user-id', 'alice']])
|
|
95
|
-
await agent.generate('List files in cwd', { requestContext: aliceCtx })
|
|
85
|
+
### `LocalSandbox`
|
|
96
86
|
|
|
97
|
-
|
|
98
|
-
const bobCtx = new RequestContext([['user-id', 'bob']])
|
|
99
|
-
await agent.generate('List files in cwd', { requestContext: bobCtx })
|
|
100
|
-
```
|
|
87
|
+
[`LocalSandbox`](https://mastra.ai/reference/workspace/local-sandbox) executes commands on the same machine as your Mastra application. By default, commands run directly on the host with the permissions of the application process.
|
|
101
88
|
|
|
102
|
-
|
|
89
|
+
Enable native isolation to restrict filesystem and network access at the operating-system level:
|
|
103
90
|
|
|
104
|
-
|
|
91
|
+
- **macOS**: Seatbelt (`sandbox-exec`)
|
|
92
|
+
- **Linux**: Bubblewrap (`bwrap`)
|
|
105
93
|
|
|
106
94
|
```typescript
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
95
|
+
const sandbox = new LocalSandbox({
|
|
96
|
+
workingDirectory: './workspace',
|
|
97
|
+
isolation: 'seatbelt', // Use 'bwrap' on Linux
|
|
98
|
+
nativeSandbox: {
|
|
99
|
+
allowNetwork: false,
|
|
100
|
+
readOnlyPaths: ['./reference-data'],
|
|
111
101
|
},
|
|
112
102
|
})
|
|
113
103
|
```
|
|
114
104
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
When the sandbox is a static instance, `workspace.init()` calls its `start()` method and `workspace.destroy()` calls its `destroy()` method. With a resolver, the workspace has no instance to manage at construction time, the caller owns the returned sandbox's lifecycle.
|
|
105
|
+
Use `LocalSandbox.detectIsolation()` to check whether Seatbelt or Bubblewrap is available on the current operating system. The `nativeSandbox` options control network access, read-only or writable paths, workspace write access, and system binaries. You can also provide a custom Seatbelt profile or Bubblewrap arguments. See [`LocalSandbox`](https://mastra.ai/reference/workspace/local-sandbox) for the full configuration.
|
|
118
106
|
|
|
119
|
-
|
|
107
|
+
### Other backends
|
|
120
108
|
|
|
121
|
-
|
|
109
|
+
Use a remote or container backend when commands need a stronger boundary from the host application. Each backend has its own isolation, persistence, networking, and mount behavior:
|
|
122
110
|
|
|
123
|
-
|
|
111
|
+
- [AgentCore](https://mastra.ai/integrations/sandboxes/agentcore)
|
|
112
|
+
- [Apple Container](https://mastra.ai/integrations/sandboxes/apple-container)
|
|
113
|
+
- [Blaxel](https://mastra.ai/integrations/sandboxes/blaxel)
|
|
114
|
+
- [Daytona](https://mastra.ai/integrations/sandboxes/daytona)
|
|
115
|
+
- [Docker](https://mastra.ai/integrations/sandboxes/docker)
|
|
116
|
+
- [E2B](https://mastra.ai/integrations/sandboxes/e2b)
|
|
117
|
+
- [Mastra](https://mastra.ai/reference/workspace/platform-sandbox)
|
|
118
|
+
- [Modal](https://mastra.ai/integrations/sandboxes/modal)
|
|
119
|
+
- [Railway](https://mastra.ai/integrations/sandboxes/railway)
|
|
120
|
+
- [Vercel](https://mastra.ai/integrations/sandboxes/vercel)
|
|
124
121
|
|
|
125
|
-
|
|
122
|
+
If Mastra doesn't support your execution backend, implement [`WorkspaceSandbox`](https://mastra.ai/reference/workspace/sandbox) to add it.
|
|
126
123
|
|
|
127
|
-
|
|
124
|
+
## Persistent storage
|
|
128
125
|
|
|
129
|
-
|
|
126
|
+
Some execution backends can also mount cloud filesystems through FUSE. Mounted files appear as local directories inside the sandbox, so commands such as `cat /data/report.md` or `python /data/analyze.py` can use them directly.
|
|
130
127
|
|
|
131
|
-
|
|
128
|
+
Configure mounts on the workspace alongside the sandbox:
|
|
132
129
|
|
|
133
130
|
```typescript
|
|
131
|
+
import { Workspace } from '@mastra/core/workspace'
|
|
132
|
+
import { DaytonaSandbox } from '@mastra/daytona'
|
|
133
|
+
import { S3Filesystem } from '@mastra/s3'
|
|
134
|
+
|
|
134
135
|
const workspace = new Workspace({
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
mounts: {
|
|
137
|
+
'/data': new S3Filesystem({
|
|
138
|
+
bucket: 'agent-data',
|
|
139
|
+
region: 'us-east-1',
|
|
140
|
+
}),
|
|
141
|
+
},
|
|
142
|
+
sandbox: new DaytonaSandbox(),
|
|
137
143
|
})
|
|
138
144
|
```
|
|
139
145
|
|
|
140
|
-
|
|
146
|
+
The agent receives filesystem tools for the mounted storage, and commands in the sandbox can access the same files under `/data`. This lets you seed an ephemeral sandbox with existing files and persist its output after the sandbox stops.
|
|
141
147
|
|
|
142
|
-
|
|
148
|
+
Mount support varies by sandbox backend. See [Filesystem](https://mastra.ai/docs/workspace/filesystem) for supported storage backends, detailed mount configuration, and how to mount multiple filesystems.
|
|
143
149
|
|
|
144
|
-
|
|
150
|
+
## Multi-tenant sandboxes
|
|
145
151
|
|
|
146
|
-
|
|
152
|
+
Use a **resolver** when each user, tenant, or thread needs a separate sandbox. Set `sandboxCacheKey` to the identity that owns the sandbox so later requests reuse the same live environment.
|
|
147
153
|
|
|
148
|
-
|
|
154
|
+
This example creates one Daytona sandbox and one S3 storage prefix per memory thread. The S3 filesystem is also mounted at `/workspace` inside the sandbox:
|
|
149
155
|
|
|
150
156
|
```typescript
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
import { MASTRA_THREAD_ID_KEY, type RequestContext } from '@mastra/core/request-context'
|
|
158
|
+
import { Workspace } from '@mastra/core/workspace'
|
|
159
|
+
import { DaytonaSandbox } from '@mastra/daytona'
|
|
160
|
+
import { S3Filesystem } from '@mastra/s3'
|
|
161
|
+
|
|
162
|
+
const getThreadId = (requestContext: RequestContext) => {
|
|
163
|
+
const threadId = requestContext.get(MASTRA_THREAD_ID_KEY)
|
|
164
|
+
if (typeof threadId !== 'string' || !threadId) {
|
|
165
|
+
throw new Error('A memory thread is required to use this workspace')
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return threadId
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const createThreadFilesystem = (threadId: string) =>
|
|
172
|
+
new S3Filesystem({
|
|
173
|
+
bucket: process.env.S3_BUCKET!,
|
|
174
|
+
region: process.env.S3_REGION!,
|
|
175
|
+
prefix: `threads/${threadId}`,
|
|
176
|
+
})
|
|
158
177
|
|
|
159
|
-
```typescript
|
|
160
178
|
const workspace = new Workspace({
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
179
|
+
filesystem: ({ requestContext }) => createThreadFilesystem(getThreadId(requestContext)),
|
|
180
|
+
sandbox: async ({ requestContext }) => {
|
|
181
|
+
const threadId = getThreadId(requestContext)
|
|
182
|
+
const sandbox = new DaytonaSandbox({
|
|
183
|
+
id: `thread-${threadId}`,
|
|
184
|
+
language: 'typescript',
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
await sandbox.start()
|
|
188
|
+
await sandbox.mount(createThreadFilesystem(threadId), '/workspace')
|
|
189
|
+
return sandbox
|
|
165
190
|
},
|
|
191
|
+
sandboxCacheKey: ({ requestContext }) => getThreadId(requestContext),
|
|
166
192
|
})
|
|
167
193
|
```
|
|
168
194
|
|
|
169
|
-
|
|
195
|
+
The first request in a thread runs the resolver and starts the sandbox. Later requests with the same thread ID reuse the cached sandbox. A different thread ID creates a different sandbox and storage prefix.
|
|
170
196
|
|
|
171
|
-
|
|
197
|
+
Workspace-level `mounts` can't be combined with a sandbox resolver. This is a known limitation, so the example mounts the filesystem inside the resolver instead. Workspace tools resolve the filesystem and sandbox from the request context automatically.
|
|
172
198
|
|
|
173
|
-
|
|
199
|
+
### Resolver ownership
|
|
174
200
|
|
|
175
|
-
|
|
176
|
-
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
177
|
-
| `execute_command` | Run a shell command. Returns stdout, stderr, and exit code. Supports `background: true` to spawn a long-running process and return a PID. |
|
|
178
|
-
| `get_process_output` | Get stdout, stderr, and status of a background process by PID. Supports `tail` to limit output lines and `wait: true` to block until exit. |
|
|
179
|
-
| `kill_process` | Stop a background process by PID. Returns recent output. |
|
|
201
|
+
The workspace doesn't own sandboxes returned by a resolver. Return a sandbox that's ready to use, and destroy it through your application's lifecycle code when it's no longer needed. `workspace.destroy()` doesn't destroy resolver-returned sandboxes.
|
|
180
202
|
|
|
181
|
-
|
|
203
|
+
Resolvers are incompatible with `mounts` and [`lsp: true`](https://mastra.ai/docs/workspace/lsp), because both require a static sandbox when the workspace is constructed. Using a resolver with `mounts` throws an `INVALID_CONFIG` error. With `lsp: true`, Mastra disables LSP and logs a warning.
|
|
182
204
|
|
|
183
|
-
|
|
205
|
+
### Tool availability
|
|
184
206
|
|
|
185
|
-
|
|
207
|
+
With a static sandbox, Mastra knows which capabilities the backend supports and only gives the agent the corresponding tools. With a resolver-backed sandbox, the backend isn't known until a request runs, so Mastra initially makes all sandbox tools available. If the resolved backend doesn't support the tool the agent calls, the call fails with `SandboxFeatureNotSupportedError`.
|
|
208
|
+
|
|
209
|
+
For example, this resolver returns a Daytona sandbox for development requests and an AgentCore sandbox for other requests:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const workspace = new Workspace({
|
|
213
|
+
sandbox: ({ requestContext }) =>
|
|
214
|
+
requestContext.get('environment') === 'development'
|
|
215
|
+
? new DaytonaSandbox()
|
|
216
|
+
: new AgentCoreRuntimeSandbox({
|
|
217
|
+
agentRuntimeArn: process.env.AGENTCORE_RUNTIME_ARN!,
|
|
218
|
+
}),
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Mastra exposes the process tools because `DaytonaSandbox` supports background processes. If a request resolves to `AgentCoreRuntimeSandbox`, one-shot commands still work, but calling `get_process_output` or `kill_process` fails with `SandboxFeatureNotSupportedError` because that backend doesn't support background processes.
|
|
223
|
+
|
|
224
|
+
## Background processes
|
|
225
|
+
|
|
226
|
+
When agents start background processes through `execute_command`, you can receive lifecycle callbacks for stdout, stderr, and process exit. Configure these through the `backgroundProcesses` option on its `WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND` entry:
|
|
186
227
|
|
|
187
228
|
```typescript
|
|
188
229
|
import { Workspace, LocalSandbox, WORKSPACE_TOOLS } from '@mastra/core/workspace'
|
|
@@ -201,45 +242,97 @@ const workspace = new Workspace({
|
|
|
201
242
|
})
|
|
202
243
|
```
|
|
203
244
|
|
|
204
|
-
These callbacks fire for all background processes started by the agent through
|
|
245
|
+
These callbacks fire for all background processes started by the agent through `execute_command`.
|
|
246
|
+
|
|
247
|
+
By default, background processes inherit the agent's abort signal and stop when the agent disconnects. Set `abortSignal` to a custom signal, or use `null` or `false` when the process should continue after the request ends.
|
|
248
|
+
|
|
249
|
+
For the full `SandboxProcessManager` API (spawning processes programmatically and reading output, plus sending stdin), see the [`SandboxProcessManager` reference](https://mastra.ai/reference/workspace/process-manager).
|
|
250
|
+
|
|
251
|
+
## Lifecycle and persistence
|
|
252
|
+
|
|
253
|
+
Sandbox scope depends on where you assign the workspace and whether you use a resolver:
|
|
205
254
|
|
|
206
|
-
|
|
255
|
+
| Configuration | Sandbox scope |
|
|
256
|
+
| ------------------------ | -------------------------------------------------------------------------------- |
|
|
257
|
+
| Mastra-level workspace | Agents that inherit the workspace from the Mastra instance use the same sandbox. |
|
|
258
|
+
| Agent-level workspace | Every request handled by that agent instance uses the same sandbox. |
|
|
259
|
+
| Resource-scoped resolver | The resolver caches one sandbox for each resource ID. |
|
|
260
|
+
| Thread-scoped resolver | A memory thread keeps its sandbox across requests in that thread. |
|
|
207
261
|
|
|
208
|
-
|
|
262
|
+
A static sandbox isn't automatically scoped to the current resource or memory thread. For resource or thread scope, use a resolver and set `sandboxCacheKey` to the corresponding ID. See [Multi-tenant sandboxes](#multi-tenant-sandboxes).
|
|
209
263
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
264
|
+
### Start
|
|
265
|
+
|
|
266
|
+
Static sandbox backends are instantiated with your application, but their execution environment usually starts lazily on the first command. Call `workspace.init()` when you want to provision it during application startup instead.
|
|
267
|
+
|
|
268
|
+
Resolver-backed sandboxes aren't started by `workspace.init()` because no backend is selected until the resolver runs. Return a sandbox that's already started or can start itself on first use.
|
|
269
|
+
|
|
270
|
+
### Hooks
|
|
271
|
+
|
|
272
|
+
Use `onStart`, `onStop`, and `onDestroy` to run application code during lifecycle transitions. Hooks receive the live sandbox instance:
|
|
213
273
|
|
|
214
274
|
```typescript
|
|
215
|
-
|
|
275
|
+
const sandbox = new LocalSandbox({
|
|
276
|
+
workingDirectory: './workspace',
|
|
277
|
+
onStart: ({ sandbox }) => console.log(`Started ${sandbox.id}`),
|
|
278
|
+
onStop: ({ sandbox }) => console.log(`Stopping ${sandbox.id}`),
|
|
279
|
+
onDestroy: ({ sandbox }) => console.log(`Destroying ${sandbox.id}`),
|
|
280
|
+
})
|
|
281
|
+
```
|
|
216
282
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
283
|
+
`onStart` runs after the sandbox starts. `onStop` and `onDestroy` run before their corresponding operation.
|
|
284
|
+
|
|
285
|
+
### Cleanup
|
|
286
|
+
|
|
287
|
+
Sandboxes passed directly to a workspace are owned by that workspace. `mastra dev` and the generated Mastra server handle shutdown signals and destroy registered workspaces automatically. If you embed Mastra in a custom server or process, call `mastra.shutdown()` from its shutdown hook. For a standalone workspace, call `workspace.destroy()` directly. The effect of stopping or destroying the underlying environment depends on the backend.
|
|
288
|
+
|
|
289
|
+
Sandboxes returned by a resolver are owned by your application. `workspace.destroy()` and `mastra.shutdown()` clear workspace references but don't destroy those resolved sandboxes. Your resolver or application lifecycle must keep track of them, call `destroy()` when their user, thread, or session ends, and then call `workspace.clearSandboxCache(cacheKey)` for keyed entries. This prevents unused compute from continuing to run and later requests from reusing a stale sandbox.
|
|
290
|
+
|
|
291
|
+
### Persistence
|
|
292
|
+
|
|
293
|
+
Persistence is backend-specific. Files and processes aren't guaranteed to survive when a sandbox stops or the application restarts. An idle timeout may also discard them. Some backends reconnect by sandbox ID or preserve snapshots and volumes. Others create a fresh environment.
|
|
294
|
+
|
|
295
|
+
Every sandbox has an `id`, but the ID isn't a cross-backend persistence guarantee. Read the selected backend's reference before relying on reconnection or persisted state.
|
|
296
|
+
|
|
297
|
+
## Network and credential safety
|
|
298
|
+
|
|
299
|
+
Mastra doesn't define one network policy that applies to every sandbox backend. Defaults and supported controls vary, so check the selected backend before running untrusted code. For sensitive or production workloads, prefer blocking outbound access or allowing only the destinations the task needs. Apply that policy when you create the sandbox so it takes effect before commands run.
|
|
300
|
+
|
|
301
|
+
If an agent starts a web server inside a remote sandbox, that server initially listens on a port inside the sandbox. Backends that support port exposure implement `sandbox.networking.getPortUrl()` to return a URL you can use to preview or test the server from outside the sandbox:
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
const url = await sandbox.networking?.getPortUrl(8000)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Depending on the backend's access controls, the URL may make the service reachable to others. This inbound exposure is separate from outbound sandbox access. `LocalSandbox` with native isolation blocks network access by default unless `allowNetwork` is enabled. Without native isolation, local commands use the host network.
|
|
308
|
+
|
|
309
|
+
For example, `DaytonaSandbox` allows outbound access unless you configure a restriction. Set `networkBlockAll` with a domain allowlist when the task only needs specific services:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { DaytonaSandbox } from '@mastra/daytona'
|
|
313
|
+
|
|
314
|
+
const sandbox = new DaytonaSandbox({
|
|
315
|
+
networkBlockAll: true,
|
|
316
|
+
domainAllowList: 'registry.npmjs.org,api.github.com',
|
|
226
317
|
})
|
|
227
318
|
```
|
|
228
319
|
|
|
229
|
-
|
|
320
|
+
Daytona applies these settings when it creates the sandbox. It also supports CIDR rules through `networkAllowList`. See the [Daytona integration page](https://mastra.ai/integrations/sandboxes/daytona) for full configuration details.
|
|
230
321
|
|
|
231
|
-
|
|
322
|
+
Environment variables passed to a sandbox or command are available to code running there. Mastra doesn't provide a backend-neutral credential broker that keeps secrets outside the sandbox while authorizing its requests. Give the command only the credentials it needs, scoped to the task. Follow the selected backend's secret-management guidance.
|
|
323
|
+
|
|
324
|
+
For example, pass a read-only token to the command that needs it instead of configuring it for every command in the sandbox:
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
await sandbox.executeCommand('node', ['scripts/download-reports.js'], {
|
|
328
|
+
env: {
|
|
329
|
+
REPORTS_READ_TOKEN: process.env.REPORTS_READ_TOKEN,
|
|
330
|
+
},
|
|
331
|
+
})
|
|
332
|
+
```
|
|
232
333
|
|
|
233
334
|
## Related
|
|
234
335
|
|
|
235
336
|
- [`SandboxProcessManager` reference](https://mastra.ai/reference/workspace/process-manager)
|
|
236
|
-
- [`
|
|
237
|
-
- [`AppleContainerSandbox` reference](https://mastra.ai/integrations/sandboxes/apple-container)
|
|
238
|
-
- [`DaytonaSandbox` reference](https://mastra.ai/integrations/sandboxes/daytona)
|
|
239
|
-
- [`E2BSandbox` reference](https://mastra.ai/integrations/sandboxes/e2b)
|
|
240
|
-
- [`LocalSandbox` reference](https://mastra.ai/reference/workspace/local-sandbox)
|
|
241
|
-
- [`ModalSandbox` reference](https://mastra.ai/integrations/sandboxes/modal)
|
|
242
|
-
- [`VercelSandbox` reference](https://mastra.ai/integrations/sandboxes/vercel)
|
|
243
|
-
- [`VercelServerlessSandbox` reference](https://mastra.ai/integrations/sandboxes/vercel)
|
|
244
|
-
- [Workspace overview](https://mastra.ai/docs/workspace/overview)
|
|
337
|
+
- [`WorkspaceSandbox` reference](https://mastra.ai/reference/workspace/sandbox)
|
|
245
338
|
- [Filesystem](https://mastra.ai/docs/workspace/filesystem)
|
|
@@ -2,10 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
# Search and indexing
|
|
4
4
|
|
|
5
|
-
**Added in:** `@mastra/core@1.1.0`
|
|
6
|
-
|
|
7
5
|
Search lets agents find relevant content in indexed workspace files. When an agent needs to answer a question or find information, it can search the indexed content instead of reading every file.
|
|
8
6
|
|
|
7
|
+
Search works with both [`mounts`](https://mastra.ai/docs/workspace/filesystem) and a [workspace-only filesystem](https://mastra.ai/docs/workspace/filesystem). With `mounts`, paths from every mounted filesystem are available through one composite filesystem. With `filesystem`, search uses that provider directly. In both cases, queries search the workspace index rather than reading live files on demand.
|
|
8
|
+
|
|
9
|
+
## When to use search
|
|
10
|
+
|
|
11
|
+
Use workspace search when your agent needs to:
|
|
12
|
+
|
|
13
|
+
- Find exact terms, filenames, or error messages with BM25 keyword search
|
|
14
|
+
- Find conceptually related content with vector search
|
|
15
|
+
- Combine keyword and semantic results with hybrid search
|
|
16
|
+
- Search a large set of files without reading each file in full
|
|
17
|
+
- Index content from files, databases, or APIs
|
|
18
|
+
|
|
19
|
+
## Quickstart
|
|
20
|
+
|
|
21
|
+
Enable BM25 search, index content, and query it through the workspace:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'
|
|
25
|
+
|
|
26
|
+
const workspace = new Workspace({
|
|
27
|
+
filesystem: new LocalFilesystem({ basePath: './workspace' }),
|
|
28
|
+
bm25: true,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
await workspace.index('/docs/guide.md', 'Reset passwords from the account settings page.')
|
|
32
|
+
|
|
33
|
+
const results = await workspace.search('password reset')
|
|
34
|
+
console.log(results)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This configuration also gives agents tools for searching and indexing workspace content.
|
|
38
|
+
|
|
9
39
|
## How it works
|
|
10
40
|
|
|
11
41
|
Workspace search has two phases: indexing and querying.
|
|
@@ -180,6 +210,8 @@ Manual indexing is useful when:
|
|
|
180
210
|
|
|
181
211
|
Configure `autoIndexPaths` to automatically index files when the workspace initializes. Each entry can be a directory path (indexed recursively) or a glob pattern for selective indexing.
|
|
182
212
|
|
|
213
|
+
`autoIndexPaths` works with a static `filesystem` or with `mounts`. For mounts, include the mount prefix in each path, such as `/docs/**/*.md`. Resolver-backed filesystems aren't auto-indexed during workspace initialization because the provider is only selected for a request; index their content manually instead.
|
|
214
|
+
|
|
183
215
|
```typescript
|
|
184
216
|
const workspace = new Workspace({
|
|
185
217
|
filesystem: new LocalFilesystem({ basePath: './workspace' }),
|
|
@@ -275,10 +307,26 @@ interface SearchResult {
|
|
|
275
307
|
|
|
276
308
|
## Agent tools
|
|
277
309
|
|
|
278
|
-
When you configure search on a workspace, agents receive
|
|
310
|
+
When you configure search on a workspace, agents receive `mastra_workspace_search` and `mastra_workspace_index` tools. Use `WORKSPACE_TOOLS.SEARCH` constants to configure them independently. For example, remove indexing when the agent should search existing content without changing the index:
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { LocalFilesystem, Workspace, WORKSPACE_TOOLS } from '@mastra/core/workspace'
|
|
314
|
+
|
|
315
|
+
const workspace = new Workspace({
|
|
316
|
+
filesystem: new LocalFilesystem({ basePath: './workspace' }),
|
|
317
|
+
bm25: true,
|
|
318
|
+
tools: {
|
|
319
|
+
[WORKSPACE_TOOLS.SEARCH.INDEX]: {
|
|
320
|
+
enabled: false,
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
})
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
See [workspace class reference](https://mastra.ai/reference/workspace/workspace-class) for the complete tool list and [`WorkspaceToolsConfig`](https://mastra.ai/reference/workspace/workspace-class) for shared settings.
|
|
279
327
|
|
|
280
328
|
## Related
|
|
281
329
|
|
|
282
|
-
- [
|
|
330
|
+
- [Sandbox](https://mastra.ai/docs/workspace/sandbox)
|
|
283
331
|
- [RAG overview](https://mastra.ai/reference/rag/overview)
|
|
284
332
|
- [Workspace class reference](https://mastra.ai/reference/workspace/workspace-class)
|