April 24, 2026
@mastra/modal)New @mastra/modal adds a Modal-backed ModalSandbox for running workspace commands in an isolated cloud environment with pause/resume support—expanding Mastra’s deployment/execution options beyond local sandboxes.
Workspace’s filesystem option now supports a resolver function, enabling per-request filesystem selection/routing from a single Workspace instance—useful for multi-tenant setups and scoped permissions without spinning up multiple Workspaces.
LSPConfigYou can now register additional language servers via lsp.servers (and override built-ins by ID), unlocking LSP-based inspection for languages beyond the default set (e.g., PHP, Ruby, Java, Kotlin, Swift, Elixir).
Workspace file indexing now auto-creates vector indices where required (e.g., LibSQL) and splits large files into overlapping chunks instead of skipping them—preventing empty vector stores and making search reliable with autoIndexPaths.
Multiple fixes prevent duplicated/replayed messages and tool outputs when observational memory is enabled (including disabling savePerStep in Harness in this mode), and agent.stream() callbacks now preserve provider-specific usage.raw so you can access cache metrics without wrapping streams.
The Workspace filesystem option now accepts a resolver function in addition to a static instance. (#13150)
Before: filesystem: WorkspaceFilesystem (static, same filesystem for every request)
After: filesystem: WorkspaceFilesystem | (({ requestContext }) => WorkspaceFilesystem) (static or per-request)
This enables per-request filesystem routing from a single Workspace — useful for multi-tenant setups, role-based access (e.g. admin vs user directories), and scoped filesystem permissions without creating separate Workspace instances.
Added support for custom language server registration with the servers field in LSPConfig. Previously, LSP inspection only worked with built-in server definitions for TypeScript, JavaScript, Python, Go, and Rust. You can now register additional language servers, such as PHP, Ruby, Java, Kotlin, Swift, or Elixir, by providing a CustomLSPServer definition. (#14969)
Example:
const workspace = new Workspace({
lsp: {
servers: {
phpactor: {
id: 'phpactor',
name: 'Phpactor Language Server',
languageIds: ['php'],
extensions: ['.php'],
markers: ['composer.json'],
command: 'phpactor language-server',
},
},
},
});
Custom servers are merged with built-in servers and can also override them by using the same ID. Closes #14828.
Update provider registry and model documentation with latest models and providers (733bf53)
Fixed output processors returning undefined from processOutputStream causing an undefined chunk to be enqueued into the consumer stream. A processor that forgets to return part (or explicitly returns undefined) now drops that chunk, matching existing null behavior, instead of emitting a bogus value to downstream readers. (#15674)
// Before: returning undefined emitted { value: undefined, done: false } to consumers
// After: returning undefined drops the chunk, same as returning null
const processor = {
id: 'my-processor',
processOutputStream: async ({ part }) => {
if (shouldDrop(part)) return; // implicit undefined — now safely dropped
return part;
},
};
Fixed streamed tool results being replayed when observational memory runs mid-stream. (#15701) Fixed observational memory markers being saved as separate empty assistant messages.
Fixed false positive provider change detection in observational memory. Message metadata now uses the configured model ID instead of the API response model ID, ensuring consistency with step-start parts and preventing incorrect 'Model changed' activations when the provider returns versioned model names (e.g., gpt-5.4-2026-03-05 vs gpt-5.4). (#15681)
Fixed interaction between savePerStep and observational memory that caused message duplication. The saveStepMessages method redundantly re-added response messages to the message list on every step, duplicating them. Additionally, savePerStep is now force-disabled when observational memory is enabled, since OM handles its own per-step persistence and the two features conflict. (#15684)
Fixed rotated response message ids not propagating to the active output stream after error processor retries, which could split a single response across two ids on the API-error retry path. (#15702)
Fixed processor-supplied options to writer.custom being dropped in the agentic execution step, so future options like transient now reach the underlying output writer.
Fixed agent.stream() callbacks so that onStepFinish and onFinish now preserve the provider-level usage.raw object on LanguageModelUsage. This lets consumers inspect provider-specific cache metrics (e.g., Anthropic and Bedrock prompt caching) directly from the callback payload without having to wrap the stream. (#15546)
Closes #15510.
Add opt-in checkSkillFileMtime option to detect in-place SKILL.md edits during hot reload. (#15676)
Previously, only directory mtime was checked for skill staleness, so editing a skill's name (to fix a validation error) or updating its description wouldn't trigger re-discovery until server restart.
The option is off by default since it doubles stat() calls per skill during staleness checks. Recommended for local development only, not for cloud storage backends where stat() has higher latency.
const myAgent = new Agent({
workspace: {
filesystem: new LocalFilesystem({ basePath: process.cwd() }),
skills: ['./**/skills'],
checkSkillFileMtime: true, // Enable for local dev
},
});
Added filterIncompleteToolCalls option to memory config. When set to false, suspended tool calls remain visible in the agent's prompt context, allowing the agent to see its own pending interactions in thread history. Defaults to true (current behavior). Useful for suspend/resume patterns with providers that support incomplete tool calls (e.g. Anthropic). (#14721)
Fixed workspace file indexing so vector search works out of the box. (#15011)
createIndex call (e.g. LibSQL) would leave the table uncreated, causing no such table errors on search. Workspaces with vectorStore + embedder + autoIndexPaths configured now work without any manual setup.Disable savePerStep in Harness to prevent duplicate messages when observational memory is enabled (#15684)
The savePerStep option in Harness caused message duplication when used alongside observational memory. This change temporarily disables savePerStep in the Harness runtime while we work on a permanent fix.
Standardize headless default to true across all browser providers. Each provider now resolves headless once in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)
Fixed browser_evaluate so expression scripts now return their computed value instead of undefined (for example, document.querySelectorAll('a').length). (#15689)
Remove unused userDataDir config option from BrowserViewerConfig. (#15696)
Standardize headless default to true across all browser providers. Each provider now resolves headless once in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)
Fix toKey() to resolve "." and "./" as the root path (#14824)
Both GCSFilesystem and S3Filesystem produced invalid object keys when called with path: "." (e.g. prefix/. instead of prefix/). Since the built-in mastra_workspace_list_files tool and Mastra Studio both default to path: ".", workspace directory listings returned empty results when backed by GCS or S3.
toKey() now normalises "." and "./" to empty string before prepending the prefix, matching the existing behaviour of "/". Dotfiles like .env or .gitignore are unaffected.
uuid with @lukeed/uuid and node:crypto (#15691)uuid with @lukeed/uuid and node:crypto (#15691)Added @mastra/modal — Modal cloud sandbox provider for Mastra workspaces. (#14486)
Use ModalSandbox to run commands in an isolated Modal environment with pause/resume support:
import { Workspace } from '@mastra/core/workspace';
import { ModalSandbox } from '@mastra/modal';
const workspace = new Workspace({
sandbox: new ModalSandbox({
tokenId: process.env.MODAL_TOKEN_ID!,
tokenSecret: process.env.MODAL_TOKEN_SECRET!,
}),
});
uuid with @lukeed/uuid and node:crypto (#15691)Fix toKey() to resolve "." and "./" as the root path (#14824)
Both GCSFilesystem and S3Filesystem produced invalid object keys when called with path: "." (e.g. prefix/. instead of prefix/). Since the built-in mastra_workspace_list_files tool and Mastra Studio both default to path: ".", workspace directory listings returned empty results when backed by GCS or S3.
toKey() now normalises "." and "./" to empty string before prepending the prefix, matching the existing behaviour of "/". Dotfiles like .env or .gitignore are unaffected.
uuid with @lukeed/uuid and node:crypto (#15691)Fixed non-Zod Standard Schema types (e.g. ArkType) being incorrectly called as lazy getters in resolveLazySchema, which caused Studio UI tool forms to receive validation errors instead of the actual JSON Schema (#15670)
Fix: Public origin resolution for AWS ALB deployments (#15666)
Implement cascading header resolution in getPublicOrigin() to properly handle:
Fixes OAuth callback URLs being resolved to http:// instead of https:// when deployed behind AWS ALB with Preserve Host Header enabled.
headless default to true across all browser providers. Each provider now resolves headless once in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)The following packages were updated with dependency changes only:
Fetched April 28, 2026
Highlights Observability Storage Domain (schemas + in-memory implementations) Mastra now ships zod-based storage schemas and in-memory impl…
Highlights Cloudflare Durable Objects Storage Adapter adds a new Durable Objects–backed storage implementation (in addition to KV), with SQ…