Mar 25, 2026
@mastra/memory now lets you route observer and reflector calls to different models based on input size using ModelByInputTokens. Short inputs can go to a fast, cheap model while longer ones get sent to a more capable one -- all configured declaratively with token thresholds. Tracing shows which model was selected and why.
@mastra/mongodb now stores versioned datasets with full item history and time-travel queries, plus experiment results and CRUD. If you're already using MongoDBStore, this works automatically with no extra setup.
New @mastra/auth-okta package brings SSO authentication and role-based access control via Okta. Map Okta groups to Mastra permissions, verify JWTs against Okta's JWKS endpoint, and manage sessions -- or pair Okta RBAC with a different auth provider like Auth0 or Clerk.
Added dataset-agent association and experiment status tracking for the Evaluate workflow. (#14470)
targetType and targetIds fields to datasets, enabling association with agents, scorers, or workflows. Datasets can now be linked to multiple entities.status field to experiment results ('needs-review', 'reviewed', 'complete') for review queue workflow.Added agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Added tool suspension handling to the Harness. (#14611)
When a tool calls suspend() during execution, the harness now emits a tool_suspended event, reports agent_end with reason 'suspended', and exposes respondToToolSuspension() to resume execution with user-provided data.
harness.subscribe((event) => {
if (event.type === "tool_suspended") {
// event.toolName, event.suspendPayload, event.resumeSchema
}
});
// Resume after collecting user input
await harness.respondToToolSuspension({ resumeData: { confirmed: true } });
Added agentId to the agent tool execution context. Tools executed by an agent can now access context.agent.agentId to identify which agent is calling them. This enables tools to look up agent metadata, share workspace configuration with sub-agents, or customize behavior per agent. (#14502)
Improved observability metrics and logs storage support. (#14607)
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
Update provider registry and model documentation with latest models and providers (68ed4e9)
Fixed Harness.destroy() to properly clean up heartbeats and workspace on teardown. (#14568)
Fixed null detection in tool input validation to check actual values at failing paths instead of relying on error message string matching. This ensures null values from LLMs are correctly handled even when validators produce error messages that don't contain the word "null" (e.g., "must be string"). Fixes #14476. (#14496)
Fixed missing tool lists in agent traces for streaming runs. Exporters like Datadog LLM Observability now receive the tools available to the agent. (#14550)
Fix consecutive tool-only loop iterations being merged into a single assistant message block. When the agentic loop runs multiple iterations that each produce only tool calls, the LLM would misinterpret them as parallel calls from a single turn. A step-start boundary is now inserted between iterations to ensure they are treated as sequential steps. (#14652)
Improved custom OpenAI-compatible model configuration guidance in the models docs. (#14594)
Added client/server body schemas for feedback and scores that omit the timestamp field, allowing it to be set server-side (#14470)
Workspace skills now surface all same-named skills for disambiguation. (#14430)
When multiple skills share the same name (e.g., a local brand-guidelines skill and one from node_modules), list() now returns all of them instead of only the tie-break winner. This lets agents and UIs see every available skill, along with its path and source type.
Tie-breaking behavior:
get(name) still returns a single skill using source-type priority: local > managed > externalget(name) throws an error — rename one or move it to a different source typeget(path) bypasses tie-breaking entirely and returns the exact skillAgents and UIs now receive all same-named skills with their paths, which improves disambiguation in prompts and tool calls.
const skills = await workspace.skills.list();
// Returns both local and external "brand-guidelines" skills
const exact = await workspace.skills.get("node_modules/@myorg/skills/brand-guidelines");
// Fetches the external copy directly by path
Fixed Anthropic 'tool_use ids were found without tool_result blocks immediately after' error. When client tools (e.g. execute_command) and provider tools (e.g. web_search) are called in parallel, the tool ordering in message history could cause Anthropic to reject subsequent requests, making the thread unrecoverable. Tool blocks are now correctly split to satisfy Anthropic's ordering requirements. (#14648)
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
fetchGroupsFromOkta now propagate so the outer .catch evicts the entry and retries on next requestid_token_hint to logout URL (required by Okta)OKTA_CLIENT_SECRET, OKTA_REDIRECT_URI, OKTA_COOKIE_PASSWORD) in README and examplesMastraAuthOktaOptions docs to include all fields (session config, scopes, etc.)getUserId cross-provider lookup pathAdded client SDK methods for dataset experiments and item generation. (#14470)
triggerExperiment() method to dataset resources for running experiments with configurable target type and IDgenerateItems() method for LLM-powered test data generationclusterFailures() method for analyzing experiment failuresAdded agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Updated skill search result types and query parameters to use skillName/skillNames instead of skillPath/skillPaths for consistency with the name-based public API. (#14430)
Added storage type detection to the Metrics Dashboard. The /system/packages endpoint now returns observabilityStorageType, identifying the observability storage backend. The dashboard shows an empty state when the storage does not support metrics (e.g. PostgreSQL, LibSQL), and displays a warning when using in-memory storage since metrics are not persisted across server restarts. Also added a docs link button to the Metrics page header. (#14620)
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient();
const system = await client.getSystemPackages();
// system.observabilityStorageType contains the class name of the observability store:
// - 'ObservabilityInMemory' → metrics work but are not persisted across restarts
// - 'ObservabilityPG', 'ObservabilityLibSQL', etc. → metrics not supported
if (system.observabilityStorageType === "ObservabilityInMemory") {
console.warn("Metrics are not persisted — data will be lost on server restart.");
}
const SUPPORTED = new Set(["ObservabilityInMemory"]);
if (!SUPPORTED.has(system.observabilityStorageType ?? "")) {
console.error("Metrics require in-memory observability storage.");
}
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added adapter auth middleware helpers for raw framework routes. (#14458)
Use createAuthMiddleware({ mastra }) when you mount routes directly on a Hono, Express, Fastify, or Koa app and still want Mastra auth to run. Set requiresAuth: false when you need to reuse the same helper chain on a public route.
app.get("/custom/protected", createAuthMiddleware({ mastra }), handler);
Added storage support for dataset targeting and experiment status fields. (#14470)
targetType (text) and targetIds (jsonb) columns to datasets table for entity associationtags (jsonb) column to datasets table for tag vocabularystatus column to experiment results for review workflow trackingAdded agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
google/gemini-2.5-flash by using stronger compression guidance and starting it at a higher compression level during reflection. google/gemini-2.5-flash is unusually good at generating long, faithful outputs. That made reflection retries more likely to preserve too much detail and miss the compression target, wasting tokens in the process. (#14612)Added datasets and experiments storage support to the MongoDB store. (#14556)
Datasets — Full dataset management with versioned items. Create, update, and delete datasets and their items with automatic version tracking. Supports batch insert/delete operations, time-travel queries to retrieve items at any past version, and item history tracking.
Experiments — Run and track experiments against datasets. Full CRUD for experiments and per-item experiment results, with pagination, filtering, and cascade deletion.
Both domains are automatically available when using MongoDBStore — no additional configuration needed.
const store = new MongoDBStore({ uri: "mongodb://localhost:27017", dbName: "my-app" });
// Datasets
const dataset = await store.getStorage("datasets").createDataset({ name: "my-dataset" });
await store.getStorage("datasets").addItem({ datasetId: dataset.id, input: { prompt: "hello" } });
// Experiments
const experiment = await store.getStorage("experiments").createExperiment({ name: "run-1", datasetId: dataset.id });
Added storage support for dataset targeting and experiment status fields. (#14470)
targetType (text) and targetIds (jsonb) columns to datasets table for entity associationtags (jsonb) column to datasets table for tag vocabularystatus column to experiment results for review workflow trackingAdded agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Added Evaluate tab to the agent playground with full dataset management, scorer editing, experiment execution, and review workflow. (#14470)
Evaluate tab — A new sidebar-driven tab for managing datasets, scorers, and experiments within the agent playground. Key features:
Review tab — A dedicated review workflow for experiment results:
Added dataset and agent version selectors to the experiment evaluate tab. You can now choose which dataset version and agent version to use when running an experiment. Version information is displayed in the experiment sidebar, results panel header, and Past Runs list. Added a copy button next to the agent version selector to easily copy version IDs. (#14562)
Added EntityList.NoMatch component that displays a message when search filtering returns no results. Applied to all entity list pages: Agents, Workflows, Tools, Scorers, Processors, Prompts, Datasets, and MCP Servers. (#14621)
Added agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Removed 'Create an Agent' button from agent list page and table empty state. Removed 'Create Scorer' button from top-level scorers page. Removed stored/code source icons (AgentSourceIcon) from agent headers, combobox, and table. Renamed 'Versions' tab to 'Editor' in agent page tabs. Added GaugeIcon to the 'Create Scorer' button in the review tab. (#14555)
Added metrics dashboard with KPI cards, trace volume, latency, model usage, and scores visualizations. Includes filtering by date range, agents, models, and providers. Added HorizontalBars, MetricsCard, MetricsKpiCard, MetricsLineChart, MetricsFlexGrid, and MetricsDataTable design system components. (#14491)
Internal cleanup and linting fixes (#14497)
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Updated skill search result types and query parameters to use skillName/skillNames instead of skillPath/skillPaths for consistency with the name-based public API. (#14430)
Added experimental entity list components with skeleton loading states, error handling, and dedicated empty state components for all list pages. Gated behind MASTRA_EXPERIMENTAL_UI environment variable. (#14547)
Added storage type detection to the Metrics Dashboard. The /system/packages endpoint now returns observabilityStorageType, identifying the observability storage backend. The dashboard shows an empty state when the storage does not support metrics (e.g. PostgreSQL, LibSQL), and displays a warning when using in-memory storage since metrics are not persisted across server restarts. Also added a docs link button to the Metrics page header. (#14620)
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient();
const system = await client.getSystemPackages();
// system.observabilityStorageType contains the class name of the observability store:
// - 'ObservabilityInMemory' → metrics work but are not persisted across restarts
// - 'ObservabilityPG', 'ObservabilityLibSQL', etc. → metrics not supported
if (system.observabilityStorageType === "ObservabilityInMemory") {
console.warn("Metrics are not persisted — data will be lost on server restart.");
}
const SUPPORTED = new Set(["ObservabilityInMemory"]);
if (!SUPPORTED.has(system.observabilityStorageType ?? "")) {
console.error("Metrics require in-memory observability storage.");
}
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
Redesigned the agent instruction blocks editor with a Notion-like document feel. Blocks no longer show line numbers or block numbers, have tighter spacing, and display a subtle hover highlight. Reference blocks now show a sync-block header with a popover for block details, "Open original", "De-reference block", and "Used by" agents. Inline blocks can be converted to saved prompt blocks via a new "Save as prompt block" action in the hover toolbar. The prompt block edit sidebar now shows a "Used by" section listing which agents reference the block. Added a lineNumbers prop to CodeEditor to optionally hide line numbers. (#14563)
<CodeEditor language="markdown" lineNumbers={false} />
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Fixed schema-compat ESM imports for Zod JSON Schema helpers. (#14617)
@mastra/schema-compat no longer uses createRequire in its Zod v4 adapter or runtime eval tests, which avoids createRequire-related ESM issues while preserving support for zod/v3 and zod/v4.
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Added dataset-agent association and experiment status tracking for the Evaluate workflow. (#14470)
targetType and targetIds fields to datasets, enabling association with agents, scorers, or workflows. Datasets can now be linked to multiple entities.status field to experiment results ('needs-review', 'reviewed', 'complete') for review queue workflow.Added getAuthenticatedUser() to @mastra/server/auth so server middleware can resolve the configured auth user without changing route auth behavior. (#14458)
Example
import { getAuthenticatedUser } from "@mastra/server/auth";
const user = await getAuthenticatedUser({
mastra,
token,
request: c.req.raw
});
Added new observability API endpoints and client methods for logs, scores, feedback, metrics (aggregate, breakdown, time series, percentiles), and discovery (metric names, label keys/values, entity types/names, service names, environments, tags) (#14470)
Added agent version support for experiments. When triggering an experiment, you can now pass an agentVersion parameter to pin which agent version to use. The agent version is stored with the experiment and returned in experiment responses. (#14562)
const client = new MastraClient();
await client.triggerDatasetExperiment({
datasetId: "my-dataset",
targetType: "agent",
targetId: "my-agent",
version: 3, // pin to dataset version 3
agentVersion: "ver_abc123" // pin to a specific agent version
});
Add optional ?path= query param to workspace skill routes for disambiguating same-named skills. (#14430)
Skill routes continue to use :skillName in the URL path (no breaking change). When two skills share the same name (e.g. from different directories), pass the optional ?path= query parameter to select the exact skill:
GET /workspaces/:workspaceId/skills/:skillName?path=skills/brand-guidelines
SkillMetadata now includes a path field, and the list() method returns all same-named skills for disambiguation. The client SDK's getSkill() accepts an optional skillPath parameter for disambiguation.
Updated skill search result types and query parameters to use skillName/skillNames instead of skillPath/skillPaths for consistency with the name-based public API. (#14430)
Added storage type detection to the Metrics Dashboard. The /system/packages endpoint now returns observabilityStorageType, identifying the observability storage backend. The dashboard shows an empty state when the storage does not support metrics (e.g. PostgreSQL, LibSQL), and displays a warning when using in-memory storage since metrics are not persisted across server restarts. Also added a docs link button to the Metrics page header. (#14620)
import { MastraClient } from "@mastra/client-js";
const client = new MastraClient();
const system = await client.getSystemPackages();
// system.observabilityStorageType contains the class name of the observability store:
// - 'ObservabilityInMemory' → metrics work but are not persisted across restarts
// - 'ObservabilityPG', 'ObservabilityLibSQL', etc. → metrics not supported
if (system.observabilityStorageType === "ObservabilityInMemory") {
console.warn("Metrics are not persisted — data will be lost on server restart.");
}
const SUPPORTED = new Set(["ObservabilityInMemory"]);
if (!SUPPORTED.has(system.observabilityStorageType ?? "")) {
console.error("Metrics require in-memory observability storage.");
}
Fix Zod v3 and Zod v4 compatibility across public structured-output APIs. (#14464)
Mastra agent and client APIs accept schemas from either zod/v3 or zod/v4, matching the documented peer dependency range and preserving TypeScript compatibility for both Zod versions.
Added ModelByInputTokens in @mastra/memory for token-threshold-based model selection in Observational Memory. (#14614)
When configured, OM automatically selects different observer or reflector models based on the actual input token count at the time the OM call runs.
Example usage:
import { Memory, ModelByInputTokens } from "@mastra/memory";
const memory = new Memory({
options: {
observationalMemory: {
model: new ModelByInputTokens({
upTo: {
10_000: "google/gemini-2.5-flash",
40_000: "openai/gpt-4o",
1_000_000: "openai/gpt-4.5"
}
})
}
}
});
The upTo keys are inclusive upper bounds. OM resolves the matching tier directly at the observer or reflector call site. If the input exceeds the largest configured threshold, OM throws an error.
Improved Observational Memory tracing so traces show the observer and reflector spans and make it easier to see which resolved model was used at runtime.
The following packages were updated with dependency changes only:
Fetched April 7, 2026