January 30, 2026
A new Workspace capability unifies agent-accessible filesystem operations, sandboxed command/code execution, keyword/semantic/hybrid search, and SKILL.md discovery with safety controls (read-only, approval flows, read-before-write guards). The Workspace is exposed end-to-end: core Workspace class (@mastra/core/workspace), server API endpoints (/workspaces/...), and new @mastra/client-js workspace client methods (files, skills, references, search).
Tracing is more actionable: listTraces now returns a status (success|error|running), spans are cleaner (inherit entity metadata, remove internal spans, emit model chunk spans for all streaming chunks), and tool approval requests are visible in traces. Token accounting for Langfuse/PostHog is corrected (cached tokens separated) and default tracing tags are preserved across exporters.
Express/Fastify/Hono/Koa adapters gain mcpOptions (notably serverless: true) to run MCP HTTP transport statelessly in serverless/edge environments without overriding response handling. Adapters and @mastra/server also add explicit requiresAuth per route (defaulting to protected), improved custom-route auth enforcement (including path params), and corrected route prefix replacement/normalization.
Tools, agents, workflows, and steps can now define a requestContextSchema (Zod) to validate required context at runtime and get typed access in execution; RequestContext.all provides convenient access to all validated values. This also flows into Studio UX (Request Context tab/forms) and fixes/improves propagation through agent networks and nested workflow execution for better observability and analytics.
text-embedding-004; use google/gemini-embedding-001 instead.@isaacs/ttlcache@^2.1.4 ↗︎ (from ^1.4.1, in dependencies)Fixes: #10184
Fixes: 1cf5d2e
Fixes: #12485
The agent record now only stores metadata fields (id, status, activeVersionId, authorId, metadata, timestamps). All configuration fields (name, instructions, model, tools, etc.) live exclusively in version snapshot rows, enabling full version history and rollback.
Key changes:
ownerId to authorId for multi-tenant filteringmemory field type from string to Record<string, unknown>status field ('draft' | 'published') to agent recordsFixes: #12488
@ai-sdk/anthropic, @ai-sdk/openai) to their correct SDK instead of falling back to openai-compatible. Add cerebras, togetherai, and deepinfra as native SDK providers.Fixes: #12450
Fixes: #12303
Fixes: #12379
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
Previously, ModelRouterLanguageModel (used when specifying models as strings like "mistral/mistral-large-latest" or "openai/gpt-4o") had supportedUrls hardcoded as an empty object. This caused Mastra to download all file URLs and convert them to bytes/base64, even when the model provider supports URLs natively.
This fix:
supportedUrls to a lazy PromiseLike that resolves the underlying model's supported URL patternsllm-execution-step.ts to properly await supportedUrls when preparing messagesImpact:
Note: Users who were relying on Mastra to download files from URLs that model providers cannot directly access (internal URLs, auth-protected URLs) may need to adjust their approach by either using base64-encoded content or ensuring URLs are publicly accessible to the model provider.
Fixes: #12167
Example:
// Working memory is loaded but agent cannot update it
const response = await agent.generate("What do you know about me?", {
memory: {
thread: "conversation-123",
resource: "user-alice-456",
options: { readOnly: true },
},
});
Fixes: #12471
Fixes: #12344
New Workspace class combines filesystem, sandbox, and search into a single interface that agents can use for file operations, command execution, and content search.
Key features:
Usage:
import { Workspace, LocalFilesystem, LocalSandbox } from '@mastra/core/workspace';
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
sandbox: new LocalSandbox({ workingDirectory: './workspace' }),
bm25: true,
});
const agent = new Agent({
workspace,
// Agent automatically receives workspace tools
});
Fixes: #11986
Fixes: #12429
Fixes: #12325
Fixes: #12220
Fixes: #12082
status field to listTraces response. The status field indicates the trace state: success (completed without error), error (has error), or running (still in progress). This makes it easier to filter and display traces by their current state without having to derive it from the error and endedAt fields.Fixes: #12213
Fixes: #12477
Before (required wrapper):
const agent = new Agent({
voice: new CompositeVoice({ output: new OpenAIVoice() }),
});
After (direct usage):
const agent = new Agent({
voice: new OpenAIVoice(),
});
Fixes: #12329
Fixes: #12346
text-embedding-004 embedding model from the model router. Google shut down this model on January 14, 2026. Use google/gemini-embedding-001 instead.Fixes: #12433
Fixes: #12396
Fixes: #12370
Fixes: #12418
RequestContext.all to access the entire RequestContext object values.const { userId, featureFlags } = requestContext.all;
Added requestContextSchema support to tools, agents, workflows, and steps. Define a Zod schema to validate and type requestContext values at runtime.
Tool example:
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
const myTool = createTool({
id: 'my-tool',
inputSchema: z.object({ query: z.string() }),
requestContextSchema: z.object({
userId: z.string(),
apiKey: z.string(),
}),
execute: async (input, context) => {
// context.requestContext is typed as RequestContext<{ userId: string, apiKey: string }>
const userId = context.requestContext?.get('userId');
return { result: 'success' };
},
});
Agent example:
import { Agent } from '@mastra/core/agent';
import { z } from 'zod';
const agent = new Agent({
name: 'my-agent',
model: openai('gpt-4o'),
requestContextSchema: z.object({
userId: z.string(),
featureFlags: z.object({
debugMode: z.boolean().optional(),
enableSearch: z.boolean().optional(),
}).optional(),
}),
instructions: ({ requestContext }) => {
// Access validated context values with type safety
const { userId, featureFlags } = requestContext.all;
const baseInstructions = `You are a helpful assistant. The current user ID is: ${userId}.`;
if (featureFlags?.debugMode) {
return `${baseInstructions} Debug mode is enabled - provide verbose responses.`;
}
return baseInstructions;
},
tools: ({ requestContext }) => {
const tools: Record<string, any> = {
weatherInfo,
};
// Conditionally add tools based on validated feature flags
const { featureFlags } = requestContext.all;
if (featureFlags?.enableSearch) {
tools['web_search_preview'] = openai.tools.webSearchPreview();
}
return tools;
},
});
Workflow example:
import { createWorkflow } from '@mastra/core/workflows';
import { z } from 'zod';
const workflow = createWorkflow({
id: 'my-workflow',
inputSchema: z.object({ data: z.string() }),
requestContextSchema: z.object({
tenantId: z.string(),
}),
});
const step = createStep({
id: 'my-step',
description: 'My step description',
inputSchema: z.object({ data: z.string() }),
outputSchema: z.object({ result: z.string() }),
requestContextSchema: z.object({
userId: z.string(),
}),
execute: async ({ inputData, requestContext }) => {
const userId = requestContext?.get('userId');
return {
result: 'some result here',
};
},
});
workflow.then(step).commit()
When requestContextSchema is defined, validation runs automatically and throws an error if required context values are missing or invalid.
Fixes: #12259
User-configured processors are now correctly passed to the routing agent, while memory-derived processors (which could interfere with routing logic) are excluded.
Fixes: #12074
Fixes: #12425
Fixes: #10184
Fixes: #12373
Fixes: #12320
Fixes: #12338
requestContext in Hono context Variables. Previously, only mastra was typed, causing TypeScript errors when accessing c.get('requestContext') even though the runtime correctly provided this context.Fixes: #12419
Example Before:
const stream = await agent.network(task);
After:
const controller = new AbortController();
const stream = await agent.network(task, {
abortSignal: controller.signal,
onAbort: ({ primitiveType, primitiveId }) => {
logger.info(`Aborted ${primitiveType}:${primitiveId}`);
},
});
controller.abort();
Related issue: #12282
Fixes: #12351
Fixes: #12122
Fixes: #12120
csv-to-questions-workflow.ts were incorrectly converted to all-lowercase (csvtoquestionsworkflow.ts) instead of proper camelCase (csvToQuestionsWorkflow.ts). PascalCase and acronym-boundary conversions are also fixed.Fixes: #12436
Fixes: #12347
Fixed TypeScript build errors when using toAISdkStream() with for await...of loops. The function now explicitly imports ReadableStream and TransformStream from 'node:stream/web', ensuring the Node.js types (which include Symbol.asyncIterator support) are used instead of global types that may not have async iterator support in all TypeScript configurations.
This resolves issue #11884 where users encountered the error: "Type 'ReadableStream<InferUIMessageChunk<UIMessage>>' must have a 'Symbol.asyncIterator' method that returns an async iterator."
Fixes: #12159
@arizeai/openinference-genai@0.1.5 ↗︎ (from 0.1.0, in dependencies)Fixes: #12146
@arizeai/openinference-semantic-conventions@^2.1.7 ↗︎ (from ^2.1.2, in dependencies)Fixes: #12147
Fixes: #12423
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
status field to listTraces response. The status field indicates the trace state: success (completed without error), error (has error), or running (still in progress). This makes it easier to filter and display traces by their current state without having to derive it from the error and endedAt fields.Fixes: #12213
The agent record now only stores metadata fields (id, status, activeVersionId, authorId, metadata, timestamps). All configuration fields (name, instructions, model, tools, etc.) live exclusively in version snapshot rows, enabling full version history and rollback.
Key changes:
ownerId to authorId for multi-tenant filteringmemory field type from string to Record<string, unknown>status field ('draft' | 'published') to agent recordsFixes: #12488
New methods on MastraClient:
listWorkspaces() - List all available workspacesgetWorkspace(workspaceId) - Get a workspace client for a specific workspaceworkspace.info() - Get workspace info and capabilitiesworkspace.listFiles() / readFile() / writeFile() / delete() / mkdir() / stat() - Filesystem operationsworkspace.listSkills() / getSkill(name).details() / .listReferences() / .getReference() - Skill managementworkspace.search() - Search indexed contentUsage:
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:4111' });
// List workspaces and get the first one
const { workspaces } = await client.listWorkspaces();
const workspace = client.getWorkspace(workspaces[0].id);
// Read a file
const { content } = await workspace.readFile('/docs/guide.md');
// List skills
const { skills } = await workspace.listSkills();
// Get skill details
const skill = workspace.getSkill('my-skill');
const details = await skill.details();
// Search content
const { results } = await workspace.search({ query: 'authentication', mode: 'hybrid' });
Fixes: #11986
Fixes: #12259
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
apiPrefix option to MastraClient for connecting to servers with custom API route prefixes.Before: The client always used the /api prefix for all endpoints.
After: You can now specify a custom prefix when deploying Mastra behind non-default paths:
const client = new MastraClient({
baseUrl: 'http://localhost:3000',
apiPrefix: '/mastra', // Calls /mastra/agents, /mastra/workflows, etc.
});
The default remains /api for backward compatibility. See #12261 for more details.
Fixes: #12295
Fixes: #12504
@mastra/client-js so stored agent edit flows work correctly. Fix stored agent schema migration in @mastra/libsql and @mastra/pg to drop and recreate the versions table when the old snapshot-based schema is detected, clean up stale draft records from partial create failures, and remove lingering legacy tables. Restores create and edit flows for stored agents.Fixes: #12504
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
@clack/prompts@1.0.0-alpha.9 ↗︎ (from 1.0.0-alpha.6, in dependencies)Fixes: #11584
workflow-get-init-data codemod that transforms getInitData() calls to getInitData<any>().This codemod helps migrate code after the getInitData return type changed from any to unknown. Adding the explicit <any> type parameter restores the previous behavior while maintaining type safety.
Usage:
npx @mastra/codemod@latest v1/workflow-get-init-data .
Before:
createStep({
execute: async ({ getInitData }) => {
const initData = getInitData();
if (initData.key === 'value') {}
},
});
After:
createStep({
execute: async ({ getInitData }) => {
const initData = getInitData<any>();
if (initData.key === 'value') {}
},
});
Fixes: #12212
mastra_workflow_snapshots index by_record_id referenced a missing id field. The id field is now explicitly defined in the Convex workflow snapshots table schema. This enables successful npx convex dev deployments that were previously failing with SchemaDefinitionError.Fixes: #12319
@babel/core@^7.28.6 ↗︎ (from ^7.28.5, in dependencies)Fixes: #12191
rollup@~4.55.1 ↗︎ (from ~4.50.2, in dependencies)Fixes: #9737
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
Fixes: #12476
Fixes: #11786
What's fixed:
hono) that aren't in your project are now resolved correctlyWhy this happened:
Previously, dependency versions were resolved at bundle time without the correct project context, causing the bundler to fall back to latest instead of using the actual installed version.
Fixes: #12125
@babel/core@^7.28.6 ↗︎ (from ^7.28.5, in dependencies)Fixes: #12191
rollup@~4.55.1 ↗︎ (from ~4.50.2, in dependencies)Fixes: #9737
Fixes: #12420
Fixes: #12505
Fixes: #12153
Fixes: #12339
mcpOptions to server adapters for serverless MCP support.Why: MCP HTTP transport uses session management by default, which requires persistent state across requests. This doesn't work in serverless environments like Cloudflare Workers or Vercel Edge where each request runs in isolation. The new mcpOptions parameter lets you enable stateless mode without overriding the entire sendResponse() method.
Before:
const server = new MastraServer({
app,
mastra,
});
// No way to pass serverless option to MCP HTTP transport
After:
const server = new MastraServer({
app,
mastra,
mcpOptions: {
serverless: true,
},
});
// MCP HTTP transport now runs in stateless mode
Fixes: #12324
Fixes: #12221
Fixes: #12153
Fixes: #12339
mcpOptions to server adapters for serverless MCP support.Why: MCP HTTP transport uses session management by default, which requires persistent state across requests. This doesn't work in serverless environments like Cloudflare Workers or Vercel Edge where each request runs in isolation. The new mcpOptions parameter lets you enable stateless mode without overriding the entire sendResponse() method.
Before:
const server = new MastraServer({
app,
mastra,
});
// No way to pass serverless option to MCP HTTP transport
After:
const server = new MastraServer({
app,
mastra,
mcpOptions: {
serverless: true,
},
});
// MCP HTTP transport now runs in stateless mode
Fixes: #12324
Fixes: #12221
@google-cloud/pubsub@^5.2.2 ↗︎ (from ^5.2.0, in dependencies)Fixes: #12265
Fixes: #12153
Fixes: #12339
Fixes: #12332
mcpOptions to server adapters for serverless MCP support.Why: MCP HTTP transport uses session management by default, which requires persistent state across requests. This doesn't work in serverless environments like Cloudflare Workers or Vercel Edge where each request runs in isolation. The new mcpOptions parameter lets you enable stateless mode without overriding the entire sendResponse() method.
Before:
const server = new MastraServer({
app,
mastra,
});
// No way to pass serverless option to MCP HTTP transport
After:
const server = new MastraServer({
app,
mastra,
mcpOptions: {
serverless: true,
},
});
// MCP HTTP transport now runs in stateless mode
Fixes: #12324
Fixes: #12221
Fixes: #12259
Fixes: #12153
Fixes: #12339
mcpOptions to server adapters for serverless MCP support.Why: MCP HTTP transport uses session management by default, which requires persistent state across requests. This doesn't work in serverless environments like Cloudflare Workers or Vercel Edge where each request runs in isolation. The new mcpOptions parameter lets you enable stateless mode without overriding the entire sendResponse() method.
Before:
const server = new MastraServer({
app,
mastra,
});
// No way to pass serverless option to MCP HTTP transport
After:
const server = new MastraServer({
app,
mastra,
mcpOptions: {
serverless: true,
},
});
// MCP HTTP transport now runs in stateless mode
Fixes: #12324
Fixes: #12221
input token count now correctly excludes cached tokens, matching each platform's expected format for accurate cost calculation. Cache read and cache write tokens are now properly reported as separate fields (cache_read_input_tokens, cache_creation_input_tokens) rather than being included in the base input count. Added defensive clamping to ensure input tokens never go negative if cache values exceed the total.Fixes: #12465
The agent record now only stores metadata fields (id, status, activeVersionId, authorId, metadata, timestamps). All configuration fields (name, instructions, model, tools, etc.) live exclusively in version snapshot rows, enabling full version history and rollback.
Key changes:
ownerId to authorId for multi-tenant filteringmemory field type from string to Record<string, unknown>status field ('draft' | 'published') to agent recordsFixes: #12488
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
status field to listTraces response. The status field indicates the trace state: success (completed without error), error (has error), or running (still in progress). This makes it easier to filter and display traces by their current state without having to derive it from the error and endedAt fields.Fixes: #12213
Fixes: #12504
@mastra/client-js so stored agent edit flows work correctly. Fix stored agent schema migration in @mastra/libsql and @mastra/pg to drop and recreate the versions table when the old snapshot-based schema is detected, clean up stale draft records from partial create failures, and remove lingering legacy tables. Restores create and edit flows for stored agents.Fixes: #12504
Fixes: #12505
Fixes: #12505
Example:
// Working memory is loaded but agent cannot update it
const response = await agent.generate("What do you know about me?", {
memory: {
thread: "conversation-123",
resource: "user-alice-456",
options: { readOnly: true },
},
});
Fixes: #12471
The agent record now only stores metadata fields (id, status, activeVersionId, authorId, metadata, timestamps). All configuration fields (name, instructions, model, tools, etc.) live exclusively in version snapshot rows, enabling full version history and rollback.
Key changes:
ownerId to authorId for multi-tenant filteringmemory field type from string to Record<string, unknown>status field ('draft' | 'published') to agent recordsFixes: #12488
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
status field to listTraces response. The status field indicates the trace state: success (completed without error), error (has error), or running (still in progress). This makes it easier to filter and display traces by their current state without having to derive it from the error and endedAt fields.Fixes: #12213
status field to listTraces response. The status field indicates the trace state: success (completed without error), error (has error), or running (still in progress). This makes it easier to filter and display traces by their current state without having to derive it from the error and endedAt fields.Fixes: #12213
Fixes: #12505
Fixes: #12220
Fixes: #12370
Fixes: #12370
Added the ability to see tool approval requests in traces for debugging purposes. When a tool requires approval, a MODEL_CHUNK span named chunk: 'tool-call-approval' is now created containing:
This enables users to debug their system by seeing approval requests in traces, making it easier to understand the flow of tool approvals and their payloads.
Fixes: #12171
The agent record now only stores metadata fields (id, status, activeVersionId, authorId, metadata, timestamps). All configuration fields (name, instructions, model, tools, etc.) live exclusively in version snapshot rows, enabling full version history and rollback.
Key changes:
ownerId to authorId for multi-tenant filteringmemory field type from string to Record<string, unknown>status field ('draft' | 'published') to agent recordsFixes: #12488
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
status field to listTraces response. The status field indicates the trace state: success (completed without error), error (has error), or running (still in progress). This makes it easier to filter and display traces by their current state without having to derive it from the error and endedAt fields.Fixes: #12213
Fixes: #12504
@mastra/client-js so stored agent edit flows work correctly. Fix stored agent schema migration in @mastra/libsql and @mastra/pg to drop and recreate the versions table when the old snapshot-based schema is detected, clean up stale draft records from partial create failures, and remove lingering legacy tables. Restores create and edit flows for stored agents.Fixes: #12504
Fixes: #12122
Fixes: #12357
Fixes: #12368
The agent record now only stores metadata fields (id, status, activeVersionId, authorId, metadata, timestamps). All configuration fields (name, instructions, model, tools, etc.) live exclusively in version snapshot rows, enabling full version history and rollback.
Key changes:
ownerId to authorId for multi-tenant filteringmemory field type from string to Record<string, unknown>status field ('draft' | 'published') to agent recordsFixes: #12488
Fixes: #12407
Fixes: #12259
Fixes: #12458
Fixes: #12377
Fixes: #11784
Fixes: #12367
Fixes: #12456
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
Fixes: #12229
Fixes: #12487
Fixes: #12409
Fixes: #12360
Fixes: #12349
Fixes: #12186
useTableKeyboardNavigation hook and isActive prop on RowFixes: #12352
Fixes: #12138
Fixes: #12350
Fixes: #12142
Fixes: #12360
Fixes: #12491
Fixes: #12256
Fixes: #12151
Fixes: #12406
Fixes: #12358
Fixes: #12497
New components:
FileBrowser - Browse and manage workspace files with breadcrumb navigationFileViewer - View file contents with syntax highlightingSkillsTable - List and search available skillsSkillDetail - View skill details, instructions, and referencesSearchPanel - Search workspace content with BM25/vector/hybrid modesReferenceViewerDialog - View skill reference file contentsUsage:
import { FileBrowser, FileViewer, SkillsTable } from '@mastra/playground-ui';
// File browser with navigation
<FileBrowser
entries={files}
currentPath="/docs"
onNavigate={setPath}
onFileSelect={handleFileSelect}
/>
// Skills table with search
<SkillsTable
skills={skills}
onSkillSelect={handleSkillSelect}
/>
Fixes: #11986
Fixes: #12410
/mastra instead of the default /api). See #12261 for more details.Fixes: #12295
input token count now correctly excludes cached tokens, matching each platform's expected format for accurate cost calculation. Cache read and cache write tokens are now properly reported as separate fields (cache_read_input_tokens, cache_creation_input_tokens) rather than being included in the base input count. Added defensive clamping to ensure input tokens never go negative if cache values exceed the total.Fixes: #12465
Extended RecursiveCharacterTransformer to support all languages defined in the Language enum. Previously, only 6 languages were supported (CPP, C, TS, MARKDOWN, LATEX, PHP), causing runtime errors for other defined languages.
Newly supported languages:
Each language has been configured with appropriate separators based on its syntax patterns (modules, classes, functions, control structures) to enable semantic code chunking.
Before:
import { RecursiveCharacterTransformer, Language } from '@mastra/rag';
// These would all throw "Language X is not supported!" errors
const goTransformer = RecursiveCharacterTransformer.fromLanguage(Language.GO);
const pythonTransformer = RecursiveCharacterTransformer.fromLanguage(Language.PYTHON);
const rustTransformer = RecursiveCharacterTransformer.fromLanguage(Language.RUST);
After:
import { RecursiveCharacterTransformer, Language } from '@mastra/rag';
// All languages now work seamlessly
const goTransformer = RecursiveCharacterTransformer.fromLanguage(Language.GO);
const goChunks = goTransformer.transform(goCodeDocument);
const pythonTransformer = RecursiveCharacterTransformer.fromLanguage(Language.PYTHON);
const pythonChunks = pythonTransformer.transform(pythonCodeDocument);
const rustTransformer = RecursiveCharacterTransformer.fromLanguage(Language.RUST);
const rustChunks = rustTransformer.transform(rustCodeDocument);
// All languages in the Language enum are now fully supported
Fixes: #12154
Previously, the Language enum defined PHP, but it was not supported in the getSeparatorsForLanguage method. This caused runtime errors when trying to use PHP for code chunking.
This change adds proper separator definitions for PHP, ensuring that PHP defined in the Language enum is now fully supported. PHP has been configured with appropriate separators based on its syntax and common programming patterns (classes, functions, control structures, etc.).
Before:
import { RecursiveCharacterTransformer, Language } from '@mastra/rag';
const transformer = RecursiveCharacterTransformer.fromLanguage(Language.PHP);
const chunks = transformer.transform(phpCodeDocument);
// Throws: "Language PHP is not supported!"
After:
import { RecursiveCharacterTransformer, Language } from '@mastra/rag';
const transformer = RecursiveCharacterTransformer.fromLanguage(Language.PHP);
const chunks = transformer.transform(phpCodeDocument);
// Successfully chunks PHP code at namespace, class, function boundaries
Fixes the issue where using Language.PHP would throw "Language PHP is not supported!" error.
Fixes: #12124
apiPrefix prop to MastraClientProvider for connecting to servers with custom API route prefixes (defaults to /api).Default usage (no change required):
<MastraClientProvider baseUrl="http://localhost:3000">
{children}
</MastraClientProvider>
Custom prefix usage:
<MastraClientProvider baseUrl="http://localhost:3000" apiPrefix="/mastra">
{children}
</MastraClientProvider>
See #12261 for more details.
Fixes: #12295
Fixes: #12138
Fixes: #12142
Fixes: #12151
The agent record now only stores metadata fields (id, status, activeVersionId, authorId, metadata, timestamps). All configuration fields (name, instructions, model, tools, etc.) live exclusively in version snapshot rows, enabling full version history and rollback.
Key changes:
ownerId to authorId for multi-tenant filteringmemory field type from string to Record<string, unknown>status field ('draft' | 'published') to agent recordsFixes: #12488
Fixes: #12481
Fixes: #12153
Fixes: #12428
Fixes: #12446
Fixes: #12259
Fixes: #12339
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
Fixes: #12332
Fixes issue where custom API routes with path parameters (e.g., /users/:id) were incorrectly requiring authentication even when requiresAuth was set to false. The authentication middleware now uses pattern matching to correctly match dynamic routes against registered patterns.
Changes:
isCustomRoutePublic() to iterate through routes and match path patternspathMatchesPattern() to support path parameters (:id), optional parameters (:id?), and wildcards (*)Fixes: #12143
Fixes: #12068
mcpOptions to server adapters for serverless MCP support.Why: MCP HTTP transport uses session management by default, which requires persistent state across requests. This doesn't work in serverless environments like Cloudflare Workers or Vercel Edge where each request runs in isolation. The new mcpOptions parameter lets you enable stateless mode without overriding the entire sendResponse() method.
Before:
const server = new MastraServer({
app,
mastra,
});
// No way to pass serverless option to MCP HTTP transport
After:
const server = new MastraServer({
app,
mastra,
mcpOptions: {
serverless: true,
},
});
// MCP HTTP transport now runs in stateless mode
Fixes: #12324
Fixes: #12251
registerApiRoute() now appear in the OpenAPI spec alongside built-in Mastra routes.Fixes: #11786
New endpoints:
GET /workspaces - List all workspaces (from Mastra instance and agents)GET /workspaces/:workspaceId - Get workspace info and capabilitiesGET/POST/DELETE /workspaces/:workspaceId/fs/* - Filesystem operations (read, write, list, delete, mkdir, stat)GET /workspaces/:workspaceId/skills - List available skillsGET /workspaces/:workspaceId/skills/:skillName - Get skill detailsGET /workspaces/:workspaceId/skills/:skillName/references - List skill referencesGET /workspaces/:workspaceId/search - Search indexed contentUsage:
// List workspaces
const { workspaces } = await fetch('/api/workspaces').then(r => r.json());
const workspaceId = workspaces[0].id;
// Read a file
const response = await fetch(`/api/workspaces/${workspaceId}/fs/read?path=/docs/guide.md`);
const { content } = await response.json();
// List skills
const skills = await fetch(`/api/workspaces/${workspaceId}/skills`).then(r => r.json());
// Search content
const results = await fetch(`/api/workspaces/${workspaceId}/search?query=authentication&mode=hybrid`)
.then(r => r.json());
Fixes: #11986
Fixes: #12295
Fixes: #12221
ws@^8.19.0 ↗︎ (from ^8.18.3, in dependencies)Fixes: #11645
ws@^8.19.0 ↗︎ (from ^8.18.3, in dependencies)Fixes: #11645
Fixes: #11784
Fixes: #12108
Fixes: #12495
mastra dev and mastra build. The CLI now checks if installed @mastra/* packages satisfy each other's peer dependency requirements and displays a warning with upgrade instructions when mismatches are detected.Fixes: #12469
Improved peer dependency version mismatch warnings in the CLI:
When the dev server crashes with an error, a hint is now shown suggesting that updating mismatched packages may fix the issue
The update command now uses the correct package manager (pnpm/npm/yarn) detected from lockfiles
The update command uses add @package@latest instead of update to ensure major version updates are applied
Added MASTRA_SKIP_PEERDEP_CHECK=1 environment variable to skip the peer dependency check
Fixes: #12479
Fixes: #11784
New Features:
Storage:
API:
Client SDK:
Usage Example:
// Server-side: Configure storage
import { Mastra } from '@mastra/core';
import { PgAgentsStorage } from '@mastra/pg';
const mastra = new Mastra({
agents: { agentOne },
storage: {
agents: new PgAgentsStorage({
connectionString: process.env.DATABASE_URL,
}),
},
});
// Client-side: Use the SDK
import { MastraClient } from '@mastra/client-js';
const client = new MastraClient({ baseUrl: 'http://localhost:3000' });
// Create a stored agent
const agent = await client.createStoredAgent({
name: 'Customer Support Agent',
description: 'Handles customer inquiries',
model: { provider: 'ANTHROPIC', name: 'claude-sonnet-4-5' },
instructions: 'You are a helpful customer support agent...',
tools: ['search', 'email'],
});
// Create a version snapshot
await client.storedAgent(agent.id).createVersion({
name: 'v1.0 - Initial release',
changeMessage: 'First production version',
});
// Compare versions
const diff = await client.storedAgent(agent.id).compareVersions('version-1', 'version-2');
Why: This feature enables teams to manage agents dynamically without code changes, making it easier to iterate on agent configurations and maintain a complete audit trail of changes.
Fixes: #12038
Fixes: #12126
--server-api-prefix option to mastra studio command for connecting to servers with custom API route prefixes.# Connect to server using custom prefix
mastra studio --server-port 3000 --server-api-prefix /mastra
Fixes: #12295
Fetched April 7, 2026