@mastra/core@1.41.0
ictnlp/LLaMA-Omni@mastra/core@1.41.0Jun 5, 2026by PaulieScanlon
AI Summary
Enhances workspace sandboxes with per-request isolation and background process continuity, while unifying 'stream until idle' behavior across SDKs.
Key Highlights
- Per-request Workspace sandboxes for multi-tenant deployments
- Sandbox continuity for background processes via `sandboxCacheKey`
- Unified 'stream until idle' behavior via `untilIdle` option
- Deprecation of dedicated `*UntilIdle` methods/endpoints
New Features
- Dynamic sandbox instructions with `instructions.dynamicSandbox` mode
- Cache management via `workspace.clearSandboxCache()`
- Support for `untilIdle` option in core, server, and client SDKs
Full Release Notes
## Highlights
### Per-request Workspace sandboxes (multi-tenant + isolation)
`@mastra/core` Workspace `sandbox` can now be a resolver function, enabling per-request sandbox routing for multi-tenant deployments with isolated working directories/permissions; includes prompt-safe “stable placeholder” instructions by default with an opt-in `instructions.dynamicSandbox` mode.
### Sandbox continuity for background processes via `sandboxCacheKey`
When using dynamic sandboxes, `sandboxCacheKey` lets background process tools (`execute_command` with `background: true`, `get_process_output`, `kill_process`) reliably attach to the same sandbox across follow-up requests, with cache management via `workspace.clearSandboxCache()`.
### Unified “stream until idle” behavior via `untilIdle` option (core + server + client SDKs)
`stream()`/`resumeStream()` now support `untilIdle` (boolean or `{ maxIdleMs }`) to keep streams open across background-task continuations; the same `untilIdle` request field is supported on server endpoints and client SDKs.
### Deprecation: dedicated `*UntilIdle` methods/endpoints
`streamUntilIdle()` and `resumeStreamUntilIdle()` (and the dedicated `/stream-until-idle` and `/resume-stream-until-idle` endpoints) are deprecated in favor of `stream(..., { untilIdle: true })` / `resumeStream(..., { untilIdle: true })`.
### Breaking Changes
- None noted in this changelog.
## Changelog
### [@mastra/core@1.41.0](https://github.com/mastra-ai/mastra/blob/@mastra/core@1.41.0/packages/core/CHANGELOG.md)
#### Minor Changes
- Workspace `sandbox` now accepts a resolver function for per-request sandboxes. ([#16048](https://github.com/mastra-ai/mastra/pull/16048))
**Before:** `sandbox: WorkspaceSandbox` (static, same sandbox for every request)
**After:** `sandbox: WorkspaceSandbox | (({ requestContext }) => WorkspaceSandbox)` (static or per-request)
This enables per-request sandbox routing from a single Workspace — useful for multi-tenant deployments where each user/role needs an isolated working directory or different execution permissions.
```ts
const workspace = new Workspace({
sandbox: ({ requestContext }) => {
const userId = requestContext.get('user-id') as string;
return new LocalSandbox({ workingDirectory: `/workspaces/${userId}` });
},
});
```
When using a resolver, the caller owns the returned sandbox's lifecycle — the Workspace will not call `start()` or `destroy()` on it. `mounts` throws an `INVALID_CONFIG` error with a resolver, and `lsp: true` is disabled with a warning because both require a concrete sandbox instance up front.
**Stable prompts by default**
Building workspace instructions no longer calls a sandbox resolver. Resolver-backed sandboxes contribute stable placeholder text to the agent's system message, so constructing the prompt never provisions a caller-owned sandbox and the prompt stays cache-friendly. Opt into concrete per-request instructions with `instructions.dynamicSandbox`:
```ts
const workspace = new Workspace({
sandbox: ({ requestContext }) => resolveSandbox(requestContext),
instructions: { dynamicSandbox: 'resolve' }, // or a ({ requestContext }) => string function
});
```
**Background process continuity**
Set `sandboxCacheKey` to keep `execute_command({ background: true })`, `get_process_output`, and `kill_process` on the same sandbox across follow-up requests — continuity is keyed by a stable id rather than the `RequestContext` instance:
```ts
const workspace = new Workspace({
sandbox: ({ requestContext }) => resolveSandbox(requestContext),
sandboxCacheKey: ({ requestContext }) => requestContext.get('thread-id') as string,
});
```
Failed sandbox resolver calls are removed from the cache so later calls can retry. Use `workspace.clearSandboxCache(cacheKey)` to drop a keyed sandbox reference when your own lifecycle code has destroyed or replaced that sandbox.
When background process tools cannot find a PID on a dynamic sandbox without `sandboxCacheKey`, the tool output now points to `sandboxCacheKey` so callers can fix continuity across follow-up requests.
#### Patch Changes
- Added `untilIdle` option to `stream()` and `resumeStream()` methods. Pass `untilIdle: true` (or `untilIdle: { maxIdleMs: 60_000 }`) to keep the stream open across background-task continuations — same behavior as the now-deprecated `streamUntilIdle()` method. ([#17536](https://github.com/mastra-ai/mastra/pull/17536))
**Example:**
```ts
const result = await agent.stream('Research solana for me', {
untilIdle: true,
memory: { thread: 't1', resource: 'u1' },
});
```
Deprecated `streamUntilIdle()` and `resumeStreamUntilIdle()` — they still work but now delegate internally to `stream({ untilIdle: true })`.
### [@mastra/acp@0.2.1](https://github.com/mastra-ai/mastra/blob/@mastra/acp@0.2.1/agent-sdks/acp/CHANGELOG.md)
#### Patch Changes
- Fixed ACP tools to keep their default session alive across executions. ([#17516](https://github.com/mastra-ai/mastra/pull/17516))
### [@mastra/client-js@1.23.2](https://github.com/mastra-ai/mastra/blob/@mastra/client-js@1.23.2/client-sdks/client-js/CHANGELOG.md)
#### Patch Changes
- The `/agents/:agentId/stream` and `/agents/:agentId/resume-stream` endpoints now accept an `untilIdle` field in the request body. When set, the stream stays open across background-task continuations (same behavior as the `/stream-until-idle` endpoint). The dedicated `/stream-until-idle` and `/resume-stream-until-idle` endpoints remain available but are deprecated. ([#17536](https://github.com/mastra-ai/mastra/pull/17536))
**Server example:**
```ts
// POST /api/agents/:agentId/stream
fetch(`/api/agents/${agentId}/stream`, {
method: 'POST',
body: JSON.stringify({
messages: [{ role: 'user', content: 'Research solana for me' }],
untilIdle: true, // or { maxIdleMs: 60000 }
}),
});
```
**Client SDK:** `streamUntilIdle()` and `resumeStreamUntilIdle()` are deprecated — use `stream(messages, { untilIdle: true })` instead.
### [@mastra/playground-ui@32.0.2](https://github.com/mastra-ai/mastra/blob/@mastra/playground-ui@32.0.2/packages/playground-ui/CHANGELOG.md)
#### Patch Changes
- Fixed dropdown, combobox, select, and popover popups silently failing to render when opened outside a side panel (most visibly the model and provider pickers in the chat composer). The shared portal-container resolver now always falls back to the document body instead of leaking an unrenderable value. ([#17560](https://github.com/mastra-ai/mastra/pull/17560))
- Fixed combobox popups so model picker dropdowns open correctly outside side dialogs. ([#17556](https://github.com/mastra-ai/mastra/pull/17556))
### [@mastra/react@0.5.2](https://github.com/mastra-ai/mastra/blob/@mastra/react@0.5.2/client-sdks/react/CHANGELOG.md)
#### Patch Changes
- The `/agents/:agentId/stream` and `/agents/:agentId/resume-stream` endpoints now accept an `untilIdle` field in the request body. When set, the stream stays open across background-task continuations (same behavior as the `/stream-until-idle` endpoint). The dedicated `/stream-until-idle` and `/resume-stream-until-idle` endpoints remain available but are deprecated. ([#17536](https://github.com/mastra-ai/mastra/pull/17536))
**Server example:**
```ts
// POST /api/agents/:agentId/stream
fetch(`/api/agents/${agentId}/stream`, {
method: 'POST',
body: JSON.stringify({
messages: [{ role: 'user', content: 'Research solana for me' }],
untilIdle: true, // or { maxIdleMs: 60000 }
}),
});
```
**Client SDK:** `streamUntilIdle()` and `resumeStreamUntilIdle()` are deprecated — use `stream(messages, { untilIdle: true })` instead.
### [@mastra/server@1.41.0](https://github.com/mastra-ai/mastra/blob/@mastra/server@1.41.0/packages/server/CHANGELOG.md)
#### Minor Changes
- The `/agents/:agentId/stream` and `/agents/:agentId/resume-stream` endpoints now accept an `untilIdle` field in the request body. When set, the stream stays open across background-task continuations (same behavior as the `/stream-until-idle` endpoint). The dedicated `/stream-until-idle` and `/resume-stream-until-idle` endpoints remain available but are deprecated. ([#17536](https://github.com/mastra-ai/mastra/pull/17536))
**Server example:**
```ts
// POST /api/agents/:agentId/stream
fetch(`/api/agents/${agentId}/stream`, {
method: 'POST',
body: JSON.stringify({
messages: [{ role: 'user', content: 'Research solana for me' }],
untilIdle: true, // or { maxIdleMs: 60000 }
}),
});
```
**Client SDK:** `streamUntilIdle()` and `resumeStreamUntilIdle()` are deprecated — use `stream(messages, { untilIdle: true })` instead.
#### Patch Changes
### Other updated packages
The following packages were updated with dependency changes only:
- [@mastra/deployer@1.41.0](https://github.com/mastra-ai/mastra/blob/@mastra/deployer@1.41.0/packages/deployer/CHANGELOG.md)
- [@mastra/deployer-cloud@1.41.0](https://github.com/mastra-ai/mastra/blob/@mastra/deployer-cloud@1.41.0/deployers/cloud/CHANGELOG.md)
- [@mastra/deployer-cloudflare@1.1.42](https://github.com/mastra-ai/mastra/blob/@mastra/deployer-cloudflare@1.1.42/deployers/cloudflare/CHANGELOG.md)
- [@mastra/deployer-netlify@1.1.18](https://github.com/mastra-ai/mastra/blob/@mastra/deployer-netlify@1.1.18/deployers/netlify/CHANGELOG.md)
- [@mastra/deployer-vercel@1.1.36](https://github.com/mastra-ai/mastra/blob/@mastra/deployer-vercel@1.1.36/deployers/vercel/CHANGELOG.md)
- [@mastra/express@1.3.29](https://github.com/mastra-ai/mastra/blob/@mastra/express@1.3.29/server-adapters/express/CHANGELOG.md)
- [@mastra/fastify@1.3.29](https://github.com/mastra-ai/mastra/blob/@mastra/fastify@1.3.29/server-adapters/fastify/CHANGELOG.md)
- [@mastra/hono@1.4.24](https://github.com/mastra-ai/mastra/blob/@mastra/hono@1.4.24/server-adapters/hono/CHANGELOG.md)
- [@mastra/koa@1.5.12](https://github.com/mastra-ai/mastra/blob/@mastra/koa@1.5.12/server-adapters/koa/CHANGELOG.md)
- [@mastra/longmemeval@1.0.48](https://github.com/mastra-ai/mastra/blob/@mastra/longmemeval@1.0.48/explorations/longmemeval/CHANGELOG.md)
- [@mastra/mcp-docs-server@1.1.45](https://github.com/mastra-ai/mastra/blob/@mastra/mcp-docs-server@1.1.45/packages/mcp-docs-server/CHANGELOG.md)
- [@mastra/nestjs@0.1.13](https://github.com/mastra-ai/mastra/blob/@mastra/nestjs@0.1.13/server-adapters/nestjs/CHANGELOG.md)
- [@mastra/opencode@0.0.45](https://github.com/mastra-ai/mastra/blob/@mastra/opencode@0.0.45/integrations/opencode/CHANGELOG.md)
- [@mastra/temporal@0.1.12](https://github.com/mastra-ai/mastra/blob/@mastra/temporal@0.1.12/workflows/temporal/CHANGELOG.md)