Highlights
Modal Cloud Sandbox Provider (@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.
Per-request Workspace Filesystem Resolver (Multi-tenant Routing)
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.
Custom Language Server Registration in LSPConfig
You 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).
Vector Search “Works Out of the Box” (Indexing + Large File Chunking)
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.
Streaming & Observational Memory Reliability + Better Usage Introspection
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.
Breaking Changes
- None noted in this changelog.
Changelog
@mastra/core@1.28.0
Minor Changes
-
The Workspace
filesystemoption 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
serversfield inLSPConfig. 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 aCustomLSPServerdefinition. (#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.
Patch Changes
-
Update provider registry and model documentation with latest models and providers (
733bf53) -
Fixed output processors returning
undefinedfromprocessOutputStreamcausing anundefinedchunk to be enqueued into the consumer stream. A processor that forgets toreturn part(or explicitly returnsundefined) now drops that chunk, matching existingnullbehavior, 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.custombeing dropped in the agentic execution step, so future options liketransientnow reach the underlying output writer. -
Fixed
agent.stream()callbacks so thatonStepFinishandonFinishnow preserve the provider-levelusage.rawobject onLanguageModelUsage. 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
checkSkillFileMtimeoption 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 wherestat()has higher latency.const myAgent = new Agent({ workspace: { filesystem: new LocalFilesystem({ basePath: process.cwd() }), skills: ['./**/skills'], checkSkillFileMtime: true, // Enable for local dev }, });
-
Added
filterIncompleteToolCallsoption to memory config. When set tofalse, suspended tool calls remain visible in the agent's prompt context, allowing the agent to see its own pending interactions in thread history. Defaults totrue(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)
- Large files that exceeded the embedding model token limit were previously silently skipped, leaving the vector store empty and causing search failures. Large files are now split into overlapping line-based chunks, each indexed separately with correct line-range tracking back to the original file.
- The vector index is now created automatically before the first upsert. Previously, backends that require an explicit
createIndexcall (e.g. LibSQL) would leave the table uncreated, causingno such tableerrors on search. Workspaces withvectorStore+embedder+autoIndexPathsconfigured now work without any manual setup.
-
Disable
savePerStepin Harness to prevent duplicate messages when observational memory is enabled (#15684)The
savePerStepoption in Harness caused message duplication when used alongside observational memory. This change temporarily disablessavePerStepin the Harness runtime while we work on a permanent fix.
@mastra/agent-browser@0.2.1
Patch Changes
-
Standardize
headlessdefault totrueacross all browser providers. Each provider now resolvesheadlessonce in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696) -
Fixed
browser_evaluateso expression scripts now return their computed value instead ofundefined(for example,document.querySelectorAll('a').length). (#15689)
@mastra/browser-viewer@0.1.1
Patch Changes
-
Remove unused
userDataDirconfig option fromBrowserViewerConfig. (#15696) -
Standardize
headlessdefault totrueacross all browser providers. Each provider now resolvesheadlessonce in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)
@mastra/gcs@0.2.1
Patch Changes
-
Fix
toKey()to resolve"."and"./"as the root path (#14824)Both
GCSFilesystemandS3Filesystemproduced invalid object keys when called withpath: "."(e.g.prefix/.instead ofprefix/). Since the built-inmastra_workspace_list_filestool and Mastra Studio both default topath: ".", 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.envor.gitignoreare unaffected.
@mastra/mcp@1.5.2
Patch Changes
- Replace
uuidwith@lukeed/uuidandnode:crypto(#15691)
@mastra/mcp-registry-registry@1.0.1
Patch Changes
- Replace
uuidwith@lukeed/uuidandnode:crypto(#15691)
@mastra/memory@1.17.1
Patch Changes
- Fixed streamed tool results being replayed when observational memory runs mid-stream. (#15701)
Fixed observational memory markers being saved as separate empty assistant messages.
@mastra/modal@0.2.0
Minor Changes
-
Added
@mastra/modal— Modal cloud sandbox provider for Mastra workspaces. (#14486)Use
ModalSandboxto 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!, }), });
Patch Changes
@mastra/mongodb@1.7.3
Patch Changes
- Replace
uuidwith@lukeed/uuidandnode:crypto(#15691)
@mastra/s3@0.4.1
Patch Changes
-
Fix
toKey()to resolve"."and"./"as the root path (#14824)Both
GCSFilesystemandS3Filesystemproduced invalid object keys when called withpath: "."(e.g.prefix/.instead ofprefix/). Since the built-inmastra_workspace_list_filestool and Mastra Studio both default topath: ".", 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.envor.gitignoreare unaffected.
@mastra/s3vectors@1.0.4
Patch Changes
- Replace
uuidwith@lukeed/uuidandnode:crypto(#15691)
@mastra/server@1.28.0
Patch Changes
-
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:
- X-Forwarded-Host (traditional reverse proxies) → always HTTPS
- Host header (AWS ALB with Preserve Host Header) → respect X-Forwarded-Proto or default HTTPS
- request.url (local development) → fallback
Fixes OAuth callback URLs being resolved to http:// instead of https:// when deployed behind AWS ALB with Preserve Host Header enabled.
@mastra/stagehand@0.2.1
Patch Changes
- Standardize
headlessdefault totrueacross all browser providers. Each provider now resolvesheadlessonce in its constructor and passes it to the thread manager via the base class getter, removing duplicate fallback logic. (#15696)
Other updated packages
The following packages were updated with dependency changes only:
- @mastra/agent-builder@1.0.29
- @mastra/client-js@1.14.2
- @mastra/deployer@1.28.0
- @mastra/deployer-cloud@1.28.0
- @mastra/deployer-cloudflare@1.1.26
- @mastra/deployer-netlify@1.1.2
- @mastra/deployer-vercel@1.1.20
- @mastra/editor@0.7.19
- @mastra/express@1.3.12
- @mastra/fastify@1.3.12
- @mastra/hono@1.4.7
- @mastra/koa@1.4.12
- @mastra/longmemeval@1.0.31
- @mastra/mcp-docs-server@1.1.28
- @mastra/opencode@0.0.28
- @mastra/playground-ui@23.0.2
- @mastra/react@0.2.29