June 26, 2026
Highlights
AI SDK v7 (LanguageModelV4) support + upgraded model router
Agents can now accept AI SDK v7 provider models directly (LanguageModelV4), while still supporting v4/v5/v6; Mastra auto-detects model spec versions so you can mix providers across agents. The model router was upgraded to resolve V4 models natively, and modelSettings adds a new reasoning effort control for V4-capable providers.
DurableAgent API parity (stream/resume/generate) + better cancellation & tracing
DurableAgent now mirrors Agent across stream/resume/generate, including full AgentExecutionOptions support (model settings, stop conditions, transforms, per-call instructions/system, tracing options, actor, etc.). New abort surfaces (abortSignal, result.abort(), onAbort) and forwarded abort to delegated subagents improve control, and durable runs now emit richer AGENT_RUN span metadata for observability.
Gateway-first model discovery & auth via new GatewayManager (Harness hooks removed)
Harness now sources model catalog, auth status, mode agents, observational-memory models, and subagents entirely from registered gateways (no fallback to resolveModel, customModelCatalogProvider, or modelAuthChecker, which were removed). Shared gateway operations are centralized in a new GatewayManager exported from @mastra/core, and gateways can implement handlesModel to claim bare provider model IDs for auth resolution.
AgentController becomes the canonical “Harness” surface across core/server/client
Harness is renamed to AgentController with a new canonical import path @mastra/core/agent-controller, and server routes are now exclusively under /agent-controller/.... Client usage follows suit (MastraClient.getAgentController, listAgentControllers, AgentControllerSession), with enriched session state (OM progress, token usage, behavior settings) and thread scoping via session tags (e.g. per git worktree).
Evals quality gates + micro-scorer checks namespace
runEvals now supports pass/fail gates, per-scorer { scorer, threshold } (including { min, max }), and returns verdict, gateResults, and thresholdResults. @mastra/evals adds checks micro-scorers (text assertions and tool-use assertions) to make common eval criteria easy to compose.
Breaking Changes
- Harness→AgentController migration:
@mastra/serverremoved legacy/harness/...routes andharness:*permissions; clients must use/agent-controller/...andagent-controller:*permissions. @mastra/client-jsremoved deprecatedgetHarness/listHarnessesandHarness/HarnessSessionclasses (breaking for recent client users).- Harness config removed
resolveModel,customModelCatalogProvider, andmodelAuthChecker; register model gateways viagatewaysinstead. - Session identity is now required:
idandownerIdare mandatory onharness.createSession()andSession/SessionIdentityconstructors (no defaults). - Workspace/browser ownership moved to per-session:
Sessionconstructor now requiresworkspace: Workspace;HarnessConfig.workspaceno longer acceptsWorkspaceConfigshorthand (must provideWorkspaceinstance or factory).
Changelog
@mastra/core@1.47.0
Minor Changes
-
Added support for AI SDK v7 models (
LanguageModelV4). You can now pass any AI SDK v7 provider model directly to an agent, alongside the existing AI SDK v4, v5, and v6 support. (#18477)import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; // AI SDK v7 const agent = new Agent({ name: 'my-agent', instructions: 'You are a helpful assistant.', model: openai('gpt-5'), });
Mastra detects the model's specification version automatically, so mixing models from different AI SDK versions across your agents continues to work without any extra configuration.
-
Finished closing the gap between
DurableAgentandAgent. After this change the durable agent surface mirrors the in-process agent's stream, resume, and generate APIs. (#18508)What's new
abortSignalonstream()andresume(), plusresult.abort()onstream(),resume(), andobserve().result.abort()onstreamUntilIdle()fans out to every inner run.untilIdleonresume()(it already existed onstream()), using the sharedrunWithIdleWrapperso both paths drive the same idle loop.DurableAgent.generate()andDurableAgent.resumeGenerate()wrapstream()/resume()and resolve aFullOutputeven when the run suspends mid-flight.delegationcallbacks (onDelegationStart,onDelegationComplete,messageFilter) are forwarded toconvertToolsat prepare time and baked into sub-agent tool wrappers.- Per-call
clientToolsandtoolsetssurvive in-process resume via the run registry (cross-process resume still falls back to the agent's static tools). - Scorers configured on the wrapped agent or passed per call now actually execute under durable runs and emit
ON_SCORER_RUNpayloads matching the non-durable shape. AGENT_RUNspans now carryconversationId,instructions,resolvedVersionId,entityVersionId, and the agent'stracingPolicy. Resume spans use'agent run: <id> (resumed)'and includeresumedFromSpanId.
Example
import { createDurableAgent } from '@mastra/core/agent/durable'; const durable = createDurableAgent({ agent: myAgent }); // 1. generate() — drains a durable run to a single FullOutput const out = await durable.generate('Plan a week in Lisbon', { abortSignal: controller.signal, modelSettings: { temperature: 0.2 }, }); // 2. stream() with result.abort() — cancel mid-run const result = await durable.stream('Long research task'); setTimeout(() => result.abort(), 5_000); for await (const chunk of result.output.fullStream) { process.stdout.write(chunk.payload?.text ?? ''); } // 3. Suspend → resumeGenerate() round-trip (e.g. tool approval) const first = await durable.generate('Run the dangerous tool', { requireToolApproval: true, }); if (first.finishReason === 'suspended') { const final = await durable.resumeGenerate(first.runId!, { approved: true }); console.log(final.text); } // 4. resume({ untilIdle }) — drive a resume through to a quiescent state await durable.resume(runId, resumeData, { untilIdle: true });
-
Brought
DurableAgent.stream()to parity withAgent.stream()for the fullAgentExecutionOptionssurface, so the same call works on both. (#18461)What's new
DurableAgent.stream()now honors these options that were previously dropped or silently coerced:- Full
modelSettings(was: onlytemperature) —maxOutputTokens,topP,topK,presencePenalty,frequencyPenalty,stopSequences,seed,headers stopWhen,prepareStep,isTaskComplete,transform- Per-call
instructionsandsystem disableBackgroundTasks,tracingOptions,actor- Function-form
requireToolApproval(toolName, args, …)(was: coerced to "approve all" — now evaluated per tool call) - New callbacks:
onAbortandonIterationComplete(joining the existingonChunk/onStepFinish/onFinish/onError/onSuspendedbridge)
Example
The same options that work on
Agent.stream()now work onDurableAgent.stream():const durable = createDurableAgent({ agent, pubsub }); await durable.stream('Plan the trip', { modelSettings: { temperature: 0.2, maxOutputTokens: 500, topP: 0.9 }, stopWhen: ({ steps }) => steps.length >= 3, prepareStep: ({ stepNumber }) => ({ activeTools: stepNumber === 0 ? ['search'] : ['book'], }), requireToolApproval: ({ toolName }) => toolName === 'book', onIterationComplete: ({ iteration }) => console.log('iter', iteration), });
- Full
-
Resolve all Harness models through gateways. The Harness now builds its available-models catalog, model auth status, mode agents, Observational Memory models, and subagents from the gateways you register, instead of the separate
resolveModel,customModelCatalogProvider, andmodelAuthCheckerconfig hooks. Removed those three options fromHarnessConfig(and theModelAuthCheckertype) — register a gateway viagatewaysinstead. (#18382)listAvailableModels()andgetCurrentModelAuthStatus()are now sourced entirely from gateways: model discovery comes from each gateway'sfetchProviders()(a network call for gateways like models.dev and Netlify), and auth status is resolved through the same gateway chain the model router uses at run time (resolveAuth(), falling back togetApiKey()). There is no static provider-registry fallback — everything the model picker shows comes from a gateway.The gateway-chain operations shared by
ModelRouterLanguageModeland the Harness (gateway merging, model→gateway selection, auth resolution, provider/model listing) are now centralized in a newGatewayManagerclass exported from@mastra/core. Both consumers delegate to it, eliminating duplicated logic.defaultGatewaysis still re-exported from the same paths for backward compatibility. -
Added
reasoningoption tomodelSettingsfor controlling model reasoning effort level. This option accepts standardized levels ('provider-default' | 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh') and is effective with LanguageModelV4 (AI SDK v7) providers that support reasoning. When used with older model providers (V2/V3), the option is a no-op. (#18500)Usage:
const result = await agent.stream('Solve this problem', { modelSettings: { reasoning: 'high' }, });
Also upgraded the model router to support LanguageModelV4, enabling native V4 model resolution alongside existing V2 and V3 models without regressions.
-
Added an optional
availableToolsallowlist toHarnessModeBaseso each mode can declare one unified list of visible tool names. When set, the harness resolvesactiveToolsat LLM-call time and hides any tool not in the list — including workspace tools, which are matched by their exposed names. Per-tool and categorydenypermission rules still take precedence over the allowlist.undefinedmeans no mode-level restriction (existing behavior). This moves mode-based tool visibility out of workspace construction and into a single, serializable contract. (#18463)Example
Declare a mode that only exposes read and plan-writing tools:
import type { HarnessMode } from '@mastra/core/harness'; const planMode: HarnessMode = { id: 'plan', // Only these tools are visible to the model in plan mode. // Workspace tools are matched by their exposed (renamed) names. availableTools: ['view', 'find_files', 'search_content', 'write_file', 'submit_plan'], // ...other mode config }; // Omitting availableTools (or setting undefined) leaves all tools visible. // Set to [] to hide every tool for this mode.
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal. -
Gates and verdict for
runEvals(#18394)New optional
gatesfield accepts scorers that must score 1.0 for the run to pass. Scorers can now use a{ scorer, threshold }form to set pass/fail thresholds.thresholdaccepts a number (minimum) or{ min, max }for range-based checks (e.g. hallucination where high = bad). The result includesverdict,gateResults, andthresholdResults. Fully backward compatible.import { runEvals } from '@mastra/core/evals'; import { checks } from '@mastra/evals/checks'; const result = await runEvals({ data: [{ input: 'What is the weather?' }], target: weatherAgent, gates: [checks.calledTool('get_weather')], scorers: [ { scorer: faithfulnessScorer, threshold: 0.7 }, { scorer: hallucinationScorer, threshold: { max: 0.3 } }, ], }); result.verdict; // 'passed' | 'scored' | 'failed'
-
Added
waitUntilsupport for channels so background agent runs survive serverless responses. (#17832)Without
waitUntil, the runtime freezes the invocation as soon as the webhook response returns, killing the agent run mid-flight and leaving the user with no reply.Auto-detected (no config needed):
- Cloudflare Workers — reads
c.executionCtx.waitUntil - Netlify Functions — reads
c.env.context.waitUntil
Requires explicit config:
Vercel needs a
waitUntilfunction passed directly because it exposeswaitUntilvia AsyncLocalStorage, not the request context. AWS Lambda doesn't needwaitUntil— it waits for the event loop to drain naturally.import { waitUntil } from '@vercel/functions'; import { SlackProvider } from '@mastra/slack'; new SlackProvider({ waitUntil });
new Agent({ channels: { adapters: { slack: createSlackAdapter({ ... }) }, waitUntil, }, });
For runtimes where
waitUntillives on the request context but isn't covered by the default, passresolveWaitUntil: (c) => fn | undefinedinstead.new Agent({ channels: { adapters: { slack: createSlackAdapter({ ... }) }, resolveWaitUntil: c => c.var.runtime?.waitUntil, }, });
Resolution order:
waitUntil→resolveWaitUntil(c)→ core default. - Cloudflare Workers — reads
-
Moved workspace and browser ownership from the Harness to individual sessions.
createSessionnow accepts optionalworkspaceandbrowseroverrides that are passed directly to theSessionconstructor. When no override is provided, the Harness-level config is used as a fallback. (#18467)Breaking changes:
Sessionconstructor now requiresworkspace: Workspaceand accepts optionalbrowser?: MastraBrowserHarnessConfig.workspaceno longer accepts aWorkspaceConfigobject — pass aWorkspaceinstance or a dynamic factory functioncreateSessionoverrides accept staticWorkspace/MastraBrowserinstances only (notDynamicArgument)- Removed
Harness.destroyWorkspace()— workspace lifecycle is now driven by per-sessionworkspace_status_changed,workspace_ready, andworkspace_errorevents emitted afterworkspace.init()completes Harness.getWorkspace()returns the static workspace instance only (returnsundefinedfor dynamic factory configs); useresolveWorkspace({ session })to resolve and cache a factory outside the request flowHarness.resolveWorkspace()now requires asessionparameter to resolve dynamic factories against the session's request context- The
SessionBusreplays the last workspace lifecycle event group to subscribers that attach after session creation, so late listeners always learn the current workspace status
Before:
const harness = new Harness({ name: 'my-harness', workspace: { name: 'my-workspace' }, // WorkspaceConfig shorthand }); const session = await harness.createSession({ resourceId: 'user-1', ownerId: 'owner-1', id: 'session-1', }); // workspace resolved lazily by the harness const ws = harness.getWorkspace();
After:
import { Workspace } from '@mastra/core'; const harness = new Harness({ name: 'my-harness', workspace: new Workspace({ name: 'my-workspace' }), }); // workspace can be overridden per session with a static instance const session = await harness.createSession({ resourceId: 'user-1', ownerId: 'owner-1', id: 'session-1', workspace: new Workspace({ name: 'ws-1' }), }); // for dynamic per-request workspaces, use the harness-level config const harness2 = new Harness({ name: 'my-harness', workspace: ({ requestContext, mastra }) => new Workspace({ name: `ws-${requestContext.session.id}` }), });
-
Surface step
providerMetadatato output-step processors (#18432)Output-step processors now receive the finishing step's provider-specific metadata through the new optional
providerMetadatafield onProcessOutputStepArgs. This lets observability and guardrail processors attribute a model response to the provider data behind it — most notably an AWS Bedrock guardrail trace on acontent-filterblock, where the completed-steps array is empty and the assessment was previously unreachable.The field is present whenever the underlying model step produced provider metadata, in both streaming and non-streaming generation. Behaviour is unchanged for steps without provider metadata.
class MyProcessor implements Processor { async processOutputStep({ finishReason, providerMetadata }: ProcessOutputStepArgs) { if (finishReason === 'content-filter') { const guardrail = providerMetadata?.bedrock?.trace?.guardrail; // attribute the block to the responsible policy/topic/filter } } }
-
Scope harness session creation with tags so sessions sharing a resourceId can (#18446)
each resume their own thread.harness.createSession()now accepts an optionaltagsrecord. The tags are
(a) seeded into the new session's state, (b) stamped onto every thread the
session creates (so thread listings can be filtered back to the session's
scope), and (c) used to filter initial thread selection: a thread is a resume
candidate only when its metadata matches every provided tag. Previously, initial
thread selection only consulted the
harness-globalinitialState.projectPath; on a multi-session server (where one
Harness serves many scopes) a session could resume the most recently updated
thread from a different scope that shared the resourceId. Using a generic tag
record (e.g.{ projectPath }) keeps room for future scoping dimensions without
further API changes.The
@mastra/client-jsHarnessSession.create()method accepts{ tags }, and
thePOST /harness/:id/sessionsroute accepts atagsbody field.// before: initial thread chosen by resourceId only const session = await harness.createSession({ resourceId, id, ownerId }); // after: initial thread scoped to this worktree via a tag const session = await harness.createSession({ resourceId, id, ownerId, tags: { projectPath: '/repo/worktree-a' }, });
Patch Changes
-
Fixed channel rendering on serverless runtimes (Vercel, AWS Lambda, Cloudflare Workers, Netlify). (#17832)
No more duplicate replies. On serverless, the same webhook event can be processed by multiple concurrent invocations. Previously each one rendered the agent reply independently, producing duplicate messages. Now only the invocation that wins the run lease renders — losers resolve cleanly without posting.
Runs no longer get killed mid-flight. The channel handler now keeps the serverless invocation alive until the agent run finishes, instead of returning immediately and relying on a background subscription that gets frozen.
Multi-step replies fully render. Agents that make multiple LLM calls per run (e.g. tool use → follow-up) now render every step's text instead of only the first.
Tool approval buttons now appear on all rendering paths. Previously, tool approval prompts (approve/deny buttons) could fail to render when using output processors. Fixed by routing
tool-call-approvalchunks through the output processor pipeline.Tool approval and decline use the same rendering path as regular messages. Approval and decline actions now flow through the per-run output processor instead of a separate subscription-based path, making rendering consistent across all message types.
User output processors now run before channel rendering. User-configured output processors (e.g. PII redaction, translation) now transform chunks before the channel renders them to the platform, instead of after.
Concurrency strategy switched to
concurrent. The chat-sdk queue lock could get stuck in frozen serverless invocations. Ordering is now handled by the signals/lease layer, removing the stale-lock failure mode. -
feat(playground): render ask_user tool as interactive question UI in Studio (#18374)
Adds an
AskUserBadgecomponent that renders suspendedask_usertool calls
as interactive prompts with clickable option buttons (single/multi-select) or
free-text input. The user's answer is sent asresumeDatathrough the existing
sendToolApprovalflow to properly resume the tool.Plumbing changes:
sendToolApprovalBodySchemanow accepts optionalresumeDataagent.sendToolApproval()passes customresumeDatawhen provided@mastra/client-jsand@mastra/reactexpose the new parameter
-
Update provider registry and model documentation with latest models and providers (
7c9dd77) -
Forward the parent
abortSignalto delegated subagents so that aborting a supervisor'sstream()orgenerate()call cancels in-flight subagents instead of letting them run to completion. (#17561)Previously, calling
AbortController.abort()on a supervisor only stopped the supervisor itself: each delegated subagent kept looping and calling its own tools and the LLM for several seconds after the abort, because the delegation tool dropped the parent'sabortSignal. The signal is now propagated to every delegation path (stream,generate,resumeStream,resumeGenerate, and the legacy variants).const controller = new AbortController(); const stream = await supervisor.stream('Research AI trends', { abortSignal: controller.signal, }); // Now also cancels any in-flight subagents, not just the supervisor controller.abort();
Fixes #14820.
-
Added
DatasetItemPayload, a new exported type describing the user-supplied fields of a dataset item. (#18489)Dataset item inputs (
AddDatasetItemInput,UpdateDatasetItemInput, and batch insert items) now share this type, so they stay consistent automatically. This is a type-only change with no runtime behavior change. -
Added
collectToolMocksexport to@mastra/core/evals. The helper walks aTrajectoryStep[]and returnsDatasetItemToolMock[], collecting top-leveltool_callandmcp_tool_callsteps in recorded order (sub-agent delegations are emitted asmatchArgs: 'ignore'). Consumers can now derive item-level tool mocks from a hydrated trajectory directly from@mastra/core. (#18488)import { collectToolMocks } from '@mastra/core/evals'; import type { Trajectory } from '@mastra/core/evals'; const mocks = collectToolMocks(trajectory.steps);
-
Fixed Studio failing to boot in the browser with
TypeError: os.tmpdir is not a function. The local sandbox resolved its mount marker directory at module-load time viaos.tmpdir(), which crashed the client bundle wherenode:oshas notmpdir. The directory is now resolved lazily, so importing the Agent runtime in the browser no longer throws. (#18524) -
Plan rejection now returns distinct tool results for inline-feedback vs. chat-based revision paths, enabling the TUI to stop the agent and wait for user chat messages. (#18323)
-
Added an optional
handlesModelhook to the model gateway interface so a gateway can claim bare provider model IDs (like__GATEWAY_ANTHROPIC_MODEL_OPUS__) it is able to authenticate, before routing falls back to the default models.dev catalog. This lets gateways that hold credentials (for example OAuth-backed logins) be selected for auth resolution and availability checks instead of being bypassed. (#18503) -
Preserved response message boundaries when processor message arrays are reapplied after output step processing. (#18337)
-
Reworked plan mode to use named plan files. The agent writes its plan to a markdown file under
.mastracode/plans/and callssubmit_planwith thepathto that file, so multiple plans stay on disk for review. The host validates the submitted path is a.mdfile inside.mastracode/plans/before reading it, so the tool can't be pointed at arbitrary files. Plan mode can write any.mdfile inside.mastracode/plans/(enforced by a tool guard) but nothing else, submitted plan snapshots are persisted for history replay, revision diffs are computed from a real line-ending-normalized LCS diff and only shown when the change is small relative to the plan, "Request Changes" stops the run immediately with no trailing model output, and diffs only compare revisions of the same plan file. (#18490) -
Fixed
InferToolInput,InferToolOutput,InferUITool, andInferUIToolsso tools created withcreateTool({ outputSchema: z.object(...) })now produce a typed{ input, output }instead of falling through tonever. UIMessage parts (tool-<name>) and other consumers can now discriminate on the inferred input/output types without manual workaround shims. (#17039)const echo = createTool({ id: 'echo', inputSchema: z.object({ x: z.string() }), outputSchema: z.object({ y: z.number() }), execute: async ({ x }) => ({ y: x.length }), }); // before: { input: never; output: never } // after: { input: { x: string }; output: { y: number } } type UI = InferUITool<typeof echo>;
Closes the gap left by #7184.
-
Fixed the in-memory workflow store resetting a run's
createdAton every re-persist, so it now matches the persistent stores. Re-persisting an existing run preserves the originalcreatedAtand only advancesupdatedAt. (#18004) -
Fixed duplicate step ID warnings in Inngest workflows. When a workflow step ran, two persistence calls with the same ID caused AUTOMATIC_PARALLEL_INDEXING warnings in Inngest logs. Steps now use unique IDs for each persistence call, eliminating the warnings. (#17320)
-
Fixed thread auto-resume selecting the wrong thread in git worktrees by scoping startup selection to threads tagged with the current project path. When Mastra Code detects a matching project thread on a different resource after resourceId drift, it now prompts before cloning and resuming that thread under the current resource; accepting the prompt leaves the old thread untouched and loads the clone, while declining starts fresh and leaves the old resource untouched. (#18333)
-
Fixed duplicate stream events when attaching to an in-progress durable or evented agent run. (#18191)
When you call
agent.observe(runId, { offset })(or reconnect to a stream with replay) whileagent.stream()is still running, the buffered portion ofoutput.textStreamcould be delivered twice before settling into normal single delivery. Late observers now receive each text-delta exactly once.Why: Two issues in the resumable-stream path could double events.
- If you passed a caching pubsub to
new Mastra({ pubsub })(e.g.withCaching(...)), the agent adopted it as its inner transport and then wrapped it again in a second caching layer sharing the same cache. Every event was stored twice, so replay delivered the buffered prefix doubled. The agent now reuses the existing caching pubsub instead of double-wrapping it.
// This setup no longer double-caches: const cache = new InMemoryServerCache(); const mastra = new Mastra({ pubsub: withCaching(new EventEmitterPubSub(), cache), cache });
- Replay/live deduplication keyed on
event.id, but the underlying pubsub regeneratesidon publish, so the cached copy and the live copy of the same event carried different ids and dedup never matched. Deduplication now keys on the event's stable sequential index, which is preserved across both paths.
- If you passed a caching pubsub to
-
Workspace skills now refresh on each skill-tool invocation, so edits to SKILL.md files (or new skills added to the workspace) are picked up between tool calls without restarting the server. Set
checkSkillFileMtime: trueon the workspace config to also detect content changes to existing SKILL.md files. Fixes #16640. (#16678) -
Fixed createTool type error when passing jsonSchema() or a Schema object from @ai-sdk/provider-utils as inputSchema — no more cast needed (#17435)
-
Fixed reasoning text being lost when agent messages are persisted to memory and recalled on the next turn (#17803)
-
Preserve original tool-call arguments when a tool result is persisted without its matching tool-call in the same message. Previously the arguments were saved as empty
{}, which poisoned the model's context and caused it to emit invalid empty-argument tool calls after a few cycles. The adapter now recovers the original arguments from prior persisted messages, covering the server resume path, AG-UI hosts replaying client-tool results, and@mastra/client-jsstreaming recursion. (#16981)Also execute every streamed client tool call emitted in the same tool-calls step before continuing, instead of only continuing with one tool result. Fixes #16017 and #15576.
-
Fixed images from tool results being dropped when using AI SDK v6 (
@ai-sdk/*v3) providers. Tools that return image data viatoModelOutput(for example screenshots) now reach the model correctly instead of arriving empty. (#18396) -
Address post-merge review follow-ups from the evented-workflow serialization work: (#18385)
Mastranow logs a warning when the TTL sweep evicts a run-scoped workflow that was still registered, surfacing abandoned suspended runs instead of dropping them silently.- The
RegExpcodec's// lgtm[js/regex-injection]suppression now spells out all three structural gates (isEnvelopelength cap + flag whitelist, local re-narrowing indecodeRegExpEnvelope,try/catchfallback) at the suppression site so future readers don't reintroduce escaping. - The
evented-unix-pubsubscenario test now allocates its Unix socket under a short/tmp/aim-*directory instead ofos.tmpdir()so it stays under the macOS 104-bytesun_pathlimit.
-
Added a browser-safe
@mastra/core/utils/collect-tool-mocksexport forcollectToolMocks. The previous@mastra/core/evalsbarrel pulls in Node-only modules (node:crypto), which broke bundling in browser apps such as the Studio playground. Import the helper from the new subpath in browser code: (#18504)import { collectToolMocks } from '@mastra/core/utils/collect-tool-mocks';
The
@mastra/core/evalsexport still works for Node-side callers. -
Fixed dynamic workspace resolution to pass the full request context to workspace factories, allowing them to access session state through getState(), and handled async stream aborts correctly so initial streamed output is preserved. (#18497)
-
Added stable session
idandownerIdto Harness sessions.SessionIdentitynow exposesgetId()andgetOwnerId(), andharness.createSession()acceptsidandownerIdto set them. These identifiers are stable for the life of the session — they do not change when the resource ID is switched — and are surfaced in the harness request context session snapshot. (#18372)Breaking change:
idandownerIdare now required on bothharness.createSession()and theSession/SessionIdentityconstructors. There are no defaults.// Before const session = new Session({ resourceId: 'my-resource' }); const session = await harness.createSession(); // After const session = new Session({ resourceId: 'my-resource', id: 'my-session-id', ownerId: 'my-owner-id', }); const session = await harness.createSession({ id: 'my-session-id', ownerId: 'my-owner-id', }); session.identity.getId(); // 'my-session-id' session.identity.getOwnerId(); // 'my-owner-id'
-
Fixed a thread becoming permanently unresponsive after a signal woke it without anyone reading the agent's response. (#18493)
When a signal woke a thread in the background and nothing consumed the resulting run, the run never finished and the thread stayed busy forever. Any further signals sent to that thread were then absorbed by the stuck run instead of starting a new one, so the agent stopped responding on that thread. Threads where you read the agent's response normally were never affected. Background-woken threads now finish on their own and keep accepting new signals.
Also fixed
consumeStream()so thatawait consumeStream()always waits for the run to actually finish, even when consumption was already started elsewhere, and so that every caller'sonErrorruns if the stream fails. -
Fixed tool-level
backgroundconfig being silently ignored. Thebackgroundoption passed tocreateToolwas accepted by the type system but never stored on the tool instance, so tools opted into background execution at the tool level always ran in the foreground. The option is now stored on the tool and dispatched as a background task. (#18454)const researchTool = createTool({ id: 'research', description: 'Run a long research job', inputSchema: z.object({ topic: z.string() }), background: { enabled: true, timeoutMs: 600_000 }, execute: async ({ topic }, context) => { // ... }, });
-
Fixed semantic recall not injecting recalled messages into the prompt when chatting through Studio. User messages sent through the agent signal pipeline (used by the Studio playground) were stored as signal rows and skipped when extracting the recall query, so recalled context never reached the model even though retrieval worked and the same request succeeded via the HTTP API. Fixes #17797 (#17818)
-
Fixed durable agents (
createDurableAgent) silently dropping stored working memory from the prompt. Working memory was saved correctly but never injected back, so per-request preferences had no effect on output. Durable preparation now establishes the memory context before resolving input processors so the working-memory injector is included. (#18411) -
Fixed conditional workflows so that re-running or rehydrating a run (time travel) no longer leaves the wrong branch marked as active. When a paused or replayed run lands on a conditional, arms whose condition does not evaluate truthy are now correctly recorded as skipped instead of staying stuck in a running state. (#18228)
The server workflow and schedule run-status response schemas now include the
'skipped'status so they stay in sync with core'sWorkflowRunStatus. -
Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
-
Removed experimental flag from retrieval-mode observational memory. The retrieval API is now stable. (#18324)
@mastra/ai-sdk@1.6.0
Minor Changes
-
Added
workflowSnapshotToStreamutility to convert aWorkflowState(as returned bygetWorkflowRunById) into an AI SDK-compatible stream. This lets you display historical workflow runs using the sameuseChat-powered UI components used for live workflow streams. (#18453)Example usage:
import { workflowSnapshotToStream } from '@mastra/ai-sdk'; import { createUIMessageStreamResponse } from 'ai'; const workflowRun = await mastra.getWorkflow('myWorkflow').getWorkflowRunById(runId); const stream = workflowSnapshotToStream(workflowRun); return createUIMessageStreamResponse({ stream });
Patch Changes
@mastra/auth@1.1.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-auth0@1.2.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-better-auth@1.1.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-clerk@1.2.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-cloud@1.2.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-firebase@1.1.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-google@0.1.0
Minor Changes
-
Added native Google Workspace authentication and group-based RBAC. (#18160)
MastraAuthGooglelets developers authenticate users with Google accounts and restrict access to trusted Google Workspace domains.MastraRBACGooglelets developers map Google Workspace groups to Mastra permissions for role-based access.
Usage:
import { MastraAuthGoogle, MastraRBACGoogle } from '@mastra/auth-google'; const mastra = new Mastra({ server: { auth: new MastraAuthGoogle({ allowedDomains: ['example.com'], }), rbac: new MastraRBACGoogle({ serviceAccount: { clientEmail: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL!, privateKey: process.env.GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY!, subject: process.env.GOOGLE_WORKSPACE_ADMIN_EMAIL!, }, roleMapping: { 'admins@example.com': ['*'], 'engineering@example.com': ['agents:*', 'workflows:*'], _default: [], }, }), }, });
@mastra/auth-okta@0.1.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-studio@1.3.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-supabase@1.1.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/auth-workos@1.6.1
Patch Changes
- Improved auth package builds by removing the direct core dependency from auth providers while preserving the existing public auth APIs. (#17142)
@mastra/client-js@1.28.0
Minor Changes
-
Enrich the agent-controller HTTP session surface so a client can render a status (#18446)
line, read behavior settings, and scope threads per working directory.GET /agent-controller/:controllerId/sessions/:resourceIdnow also returns:omProgress— the status-line slice of observational-memory progress
(pending tokens vs. observation threshold, accumulated observations vs.
reflection threshold, plus projected message removal / reflection savings)tokenUsage— cumulative token usage for the current threadsettings— agent behavior settings (yolo,thinkingLevel,
notifications,smartEditing)
GET /agent-controller/:controllerId/sessions/:resourceId/threadsaccepts
an optionaltagsquery param (a JSON-encoded object). A single resourceId can
be shared across git worktrees of the same repo (the id is derived from the git
URL), so passingtagsscopes the list to threads matching every tag (e.g.
{ projectPath }for the working directory). Each returned thread now also
includes the scopingtagsit was stamped with at creation.The session event stream route (
.../stream) now enqueues raw event objects
and lets the server adapter handle SSE framing, fixing a double-framing bug
where events were wrapped twice (data: "data: {...}\n\n"\n\n) and could not be
parsed by clients.@mastra/client-jsgains the matching types and reads:AgentControllerOMProgressandAgentControllerSessionSettings, surfaced on
AgentControllerSessionState(omProgress,tokenUsage,settings)- a
display_state_changedevent inKnownAgentControllerEventcarrying the
status-line figures AgentControllerSession.listThreads()now accepts either a number
(back-compat) or{ limit?, tags? }
Example:
const session = client.getAgentController('code').session(resourceId); // Scope a worktree's thread list (and resumed session) to its own threads. await session.create({ tags: { projectPath: '/repo/worktree-a' } }); const threads = await session.listThreads({ tags: { projectPath: '/repo/worktree-a' } }); // Read the status-line figures and agent settings. const state = await session.state(); state.omProgress; // observational-memory progress state.tokenUsage; // cumulative token usage state.settings; // { yolo, thinkingLevel, notifications, smartEditing }
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal. -
Scope harness session creation with tags so sessions sharing a resourceId can (#18446)
each resume their own thread.harness.createSession()now accepts an optionaltagsrecord. The tags are
(a) seeded into the new session's state, (b) stamped onto every thread the
session creates (so thread listings can be filtered back to the session's
scope), and (c) used to filter initial thread selection: a thread is a resume
candidate only when its metadata matches every provided tag. Previously, initial
thread selection only consulted the
harness-globalinitialState.projectPath; on a multi-session server (where one
Harness serves many scopes) a session could resume the most recently updated
thread from a different scope that shared the resourceId. Using a generic tag
record (e.g.{ projectPath }) keeps room for future scoping dimensions without
further API changes.The
@mastra/client-jsHarnessSession.create()method accepts{ tags }, and
thePOST /harness/:id/sessionsroute accepts atagsbody field.// before: initial thread chosen by resourceId only const session = await harness.createSession({ resourceId, id, ownerId }); // after: initial thread scoped to this worktree via a tag const session = await harness.createSession({ resourceId, id, ownerId, tags: { projectPath: '/repo/worktree-a' }, });
Patch Changes
-
feat(playground): render ask_user tool as interactive question UI in Studio (#18374)
Adds an
AskUserBadgecomponent that renders suspendedask_usertool calls
as interactive prompts with clickable option buttons (single/multi-select) or
free-text input. The user's answer is sent asresumeDatathrough the existing
sendToolApprovalflow to properly resume the tool.Plumbing changes:
sendToolApprovalBodySchemanow accepts optionalresumeDataagent.sendToolApproval()passes customresumeDatawhen provided@mastra/client-jsand@mastra/reactexpose the new parameter
-
Preserve original tool-call arguments when a tool result is persisted without its matching tool-call in the same message. Previously the arguments were saved as empty
{}, which poisoned the model's context and caused it to emit invalid empty-argument tool calls after a few cycles. The adapter now recovers the original arguments from prior persisted messages, covering the server resume path, AG-UI hosts replaying client-tool results, and@mastra/client-jsstreaming recursion. (#16981)Also execute every streamed client tool call emitted in the same tool-calls step before continuing, instead of only continuing with one tool result. Fixes #16017 and #15576.
@mastra/deployer@1.47.0
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal. -
Add the experimental Signals observability experience to Studio. Introduces a route-driven enterprise topics/signals trace explorer (topic, subtopic, and trace panels) and a reusable scatter plot chart component in
@mastra/playground-ui, with the reusable Signals UI and data placed behind the playground-ui EE export boundary. The Signals page is gated behind a server-injectedMASTRA_SIGNALS_UIruntime flag: the Studio HTML exposeswindow.MASTRA_SIGNALS_UI, which the CLI and deployers populate from theMASTRA_SIGNALS_UIenv var (default off). When disabled, the Signals sidebar item and/signalsroutes are not registered. (#18138)
@mastra/deployer-cloud@1.47.0
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/deployer-cloudflare@1.2.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/deployer-netlify@1.2.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/deployer-vercel@1.2.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/dynamodb@1.1.1
Patch Changes
- Fixed workflow runs preserving their original creation time when re-persisted in DynamoDB storage, including concurrent saves. (#18004)
@mastra/e2b@0.4.1
Patch Changes
-
Make concurrent S3 and GCS mounts reliable in the same sandbox (#18512)
Mounting several buckets at once, or restoring mounts after a pause/resume, could previously fail or pick up the wrong credentials because every mount shared one temporary credentials file and overwrote each other's. Each mount now gets its own credentials file, so they no longer interfere. (Azure already worked this way.)
@mastra/evals@1.5.0
Minor Changes
-
Added
checks, a new namespace of micro-scorers for common eval assertions. (#18392)What changed
- Added text checks:
includes,excludes,equals,matches, andsimilarity. - Added tool checks:
calledTool,didNotCall,toolOrder,maxToolCalls,usedNoTools, andnoToolErrors. - You can now import checks from
@mastra/evals/checks.
Example
import { checks } from '@mastra/evals/checks'; const scorers = [ checks.includes('sunny'), checks.calledTool('get_weather'), checks.toolOrder(['search', 'summarize']), checks.noToolErrors(), ];
- Added text checks:
Patch Changes
-
Gates and verdict for
runEvals(#18394)New optional
gatesfield accepts scorers that must score 1.0 for the run to pass. Scorers can now use a{ scorer, threshold }form to set pass/fail thresholds.thresholdaccepts a number (minimum) or{ min, max }for range-based checks (e.g. hallucination where high = bad). The result includesverdict,gateResults, andthresholdResults. Fully backward compatible.import { runEvals } from '@mastra/core/evals'; import { checks } from '@mastra/evals/checks'; const result = await runEvals({ data: [{ input: 'What is the weather?' }], target: weatherAgent, gates: [checks.calledTool('get_weather')], scorers: [ { scorer: faithfulnessScorer, threshold: 0.7 }, { scorer: hallucinationScorer, threshold: { max: 0.3 } }, ], }); result.verdict; // 'passed' | 'scored' | 'failed'
@mastra/express@1.4.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/fastify@1.4.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/github-signals@0.2.2
Patch Changes
- Avoided reapplying unchanged messages when GitHub signals only emit subscription hint side effects. (#18337)
@mastra/hono@1.5.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/koa@1.6.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/libsql@1.14.2
Patch Changes
- Fixed
persistWorkflowSnapshotresetting a workflow run'screatedAton every re-persist. The default execution engine re-persists a run's snapshot on every step, socreatedAtdrifted to the last activity time and jumped forward on suspend/resume. Re-persisting now preserves the originalcreatedAtand only advancesupdatedAt, solistWorkflowRunsordering, fromDate/toDate filters, and the creation time shown in Studio stay correct. (#18004)
@mastra/memory@1.21.2
Patch Changes
-
Fixed unhandled promise rejection when async buffered observation fails due to missing catch handler (#18026)
-
Removed experimental flag from retrieval-mode observational memory. The retrieval API is now stable. (#18324)
@mastra/mysql@0.3.1
Patch Changes
-
Fixed workflow snapshots and AI spans creating duplicate records instead of updating in place. Each workflow step previously inserted a new row, causing unbounded table growth and degraded read performance. (#18460)
-
Fixed workflow runs preserving their original creation time when re-persisted in MySQL storage, including concurrent saves. (#18004)
@mastra/nestjs@0.2.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/next@0.2.1
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/observability@1.15.2
Patch Changes
-
Fixed pricing lookup when a provider-reported response model does not match a known pricing entry but the configured model does. Cost estimation now falls back to the configured model before reporting
no_matching_model. (#16585) -
Tool telemetry is now more informative for tools that transform their output before sending to the model. Tool-result spans in traces show the actual value the model received instead of being empty, and step input previews display the tool result content instead of an opaque
[tool-result]placeholder. This makes it easier to debug tool behavior in Langfuse, Datadog, and other observability providers. (#18417)
@mastra/otel-bridge@1.4.0
Minor Changes
-
Added
tracerProviderandloggerProvideroptions toOtelBridgeConfig, allowing spans and logs to be routed to non-global OpenTelemetry providers. (#18185)import { OtelBridge } from '@mastra/otel-bridge'; const bridge = new OtelBridge({ tracerProvider: myLangfuseTracerProvider, loggerProvider: myCustomLoggerProvider, });
Both fields are optional and default to the global provider when omitted — no breaking changes.
Patch Changes
@mastra/pg@1.14.2
Patch Changes
-
Fixed workflow runs advancing their update time when re-persisted in PostgreSQL storage. (#18004)
-
Fixed PgVector numeric range filters (
$gt,$gte,$lt,$lte) so rows with non-numeric metadata values no longer fail the whole query. (#18430)A single document with a value like
{ price: 'N/A' }used to make the entire query error out, breaking all range-filtered vector queries (and semantic recall usingsemanticRecall.filter) on that index. Rows whose value isn't a number are now skipped for numeric range checks instead, matching the behavior of the other Mastra vector stores. Numeric rows still match as expected.await pgVector.upsert({ indexName: 'products', vectors: [ [1, 0], [0, 1], ], metadata: [{ price: 100 }, { price: 'N/A' }], }); // Before: threw "invalid input syntax for type numeric: N/A" // After: returns only the row whose price is actually a number await pgVector.query({ indexName: 'products', queryVector: [1, 0], topK: 10, filter: { price: { $gt: 50 } }, });
-
Negated numeric range filters (
$notwith$gt,$gte,$lt,$lte) now correctly exclude rows where the filtered field is missing or non-numeric. Previously these rows were incorrectly included in results. (#18466)
@mastra/playground-ui@37.0.0
Minor Changes
-
Added a reusable environment variables editor with .env import, bulk paste support, and custom-row hook support. (#18371)
import { EnvironmentVariablesEditor, useEnvironmentVariablesEditor } from '@mastra/playground-ui'; function SettingsEnvVars() { const editor = useEnvironmentVariablesEditor({ initialRows: [{ key: 'PUBLIC_BASE_URL', value: 'https://example.com' }], }); return ( <EnvironmentVariablesEditor editor={editor} actions={ <button type="button" onClick={() => editor.getEnvironmentVariablesForSubmit()}> Save </button> } /> ); }
-
Added sticky row headers to DataList. (#18222)
Use
sticky="start"on the leadingDataList.TopCelland render matching row cells withDataList.RowHeaderCell:<DataList columns="auto auto auto" variant="lined"> <DataList.Top> <DataList.TopCell sticky="start">Model</DataList.TopCell> <DataList.TopCell>Input</DataList.TopCell> <DataList.TopCell>Output</DataList.TopCell> </DataList.Top> <DataList.RowStatic> <DataList.RowHeaderCell>Model A</DataList.RowHeaderCell> <DataList.Cell>1,200</DataList.Cell> <DataList.Cell>800</DataList.Cell> </DataList.RowStatic> </DataList>
Metrics tables now render directly through DataList so sticky row headers share the same header colors and hover treatment as the rest of the list system. Metrics tables also follow the default DataList variant, and sticky row headers use the same neutral header treatment as column headers.
DataList now exposes
stickyHeaderBackgroundto keep the top header and sticky row-header fill in sync, and forwardsmaskto the underlying ScrollArea so sticky-start tables can disable the left edge fade.Added
DataList.NumberCellfor right-aligned numeric columns. It bakes in the tabular-figure, compact metric-table styling, with ahighlightprop for the emphasized value:<DataList.NumberCell>1,200</DataList.NumberCell> <DataList.NumberCell highlight>$0.42</DataList.NumberCell>
The metrics-specific
MetricsDataTablewrapper was removed. Use DataList for DS-owned metrics table layouts. -
Add the experimental Signals observability experience to Studio. Introduces a route-driven enterprise topics/signals trace explorer (topic, subtopic, and trace panels) and a reusable scatter plot chart component in
@mastra/playground-ui, with the reusable Signals UI and data placed behind the playground-ui EE export boundary. The Signals page is gated behind a server-injectedMASTRA_SIGNALS_UIruntime flag: the Studio HTML exposeswindow.MASTRA_SIGNALS_UI, which the CLI and deployers populate from theMASTRA_SIGNALS_UIenv var (default off). When disabled, the Signals sidebar item and/signalsroutes are not registered. (#18138)
Patch Changes
-
Fixed overlay content components to support Base UI positioning options. (#18431)
-
Added direct Playground UI subpaths for shared helpers so apps can avoid the root barrel when importing existing utility and rule builder APIs. (#18502)
import { is401UnauthorizedError } from '@mastra/playground-ui/utils/errors'; import type { JsonSchema } from '@mastra/playground-ui/utils/json-schema'; import { RuleBuilder } from '@mastra/playground-ui/components/RuleBuilder';
-
Show an unavailable state when the configured observability storage does not support listing logs, and stop polling the logs endpoint for that non-transient capability error. (#18375)
-
Added a direct utility import for the class name helper so applications can avoid the root Playground UI barrel. (#18458)
import { cn } from '@mastra/playground-ui/utils/cn';
-
Added direct import paths for toast and Playground UI icons so apps can avoid the root Playground UI barrel when using high-traffic utilities and icon components. (#18470)
import { Toaster } from '@mastra/playground-ui/components/Toaster'; import { AgentIcon } from '@mastra/playground-ui/icons/AgentIcon'; import { toast } from '@mastra/playground-ui/utils/toast';
-
Move the Memory Studio (timeline, flamegraph, and observational-memory detail) into the agent chat view as an opt-in panel. (#18272)
- The standalone Memory nav entry,
/memoryroutes, and the separate thread/chat list are removed; the studio is now opened from the chat view and shown inside the Memory sidepanel, with the agent layout's left resizable panel expanding when the detail opens. Clicking the flamegraph timeline drives a replay cursor that highlights the matching observational-memory record. Marker types are imported from@mastra/memoryinstead of being redeclared in the UI so the studio stays in sync with the stream format. MemoryStudioPanelgains an optionalcontextWindowprop so callers can supply authoritative message/observation token counts and thresholds; when provided these take precedence over values re-derived from message markers, keeping the panel's MESSAGES/OBSERVATIONS readout in sync with the observational-memory sidebar (marker-derived values remain the fallback for standalone usage).MemoryStudioPanelnow shows both Messages and Observations progress bars, matching the collapsed memory sidebar. The FlameGraph zoom range is lifted into the panel and filters the observation list: collapsing the range hides out-of-range observations and "Reset zoom" restores the full list.FlameGraphgains optional controlledzoomRange/onZoomRangeChangeprops (uncontrolled usage is unchanged).
- The standalone Memory nav entry,
@mastra/react@1.2.0
Minor Changes
-
Added
tasksas a first-class return value onuseChat. Task state is incrementally updated from streaming task state signals and tool results — no message rescanning required. (#18374)Fixed step framing markers leaking into the chat UI. The MessageFactory now renders step-start parts as nothing by default instead of routing them to your fallback renderer, so internal step boundaries no longer show up as stray output. You can still opt in to rendering a step divider by supplying a StepStart renderer.
Patch Changes
-
feat(playground): render ask_user tool as interactive question UI in Studio (#18374)
Adds an
AskUserBadgecomponent that renders suspendedask_usertool calls
as interactive prompts with clickable option buttons (single/multi-select) or
free-text input. The user's answer is sent asresumeDatathrough the existing
sendToolApprovalflow to properly resume the tool.Plumbing changes:
sendToolApprovalBodySchemanow accepts optionalresumeDataagent.sendToolApproval()passes customresumeDatawhen provided@mastra/client-jsand@mastra/reactexpose the new parameter
@mastra/redis@1.2.1
Patch Changes
nodeRedisPresetnow adapts the three list operations (llen,rpush,lrange) to their camelCase forms onnode-redisv4+ clients (lLen,rPush,lRange). Extends the same adapter pattern already used forsetandscan. ioredis and Upstash users are unaffected (defaults remain lowercase, matching their APIs). (#18408)
@mastra/schema-compat@1.3.1
Patch Changes
- Fixed createTool type error when passing jsonSchema() or a Schema object from @ai-sdk/provider-utils as inputSchema — no more cast needed (#17435)
@mastra/server@1.47.0
Minor Changes
-
Enrich the agent-controller HTTP session surface so a client can render a status (#18446)
line, read behavior settings, and scope threads per working directory.GET /agent-controller/:controllerId/sessions/:resourceIdnow also returns:omProgress— the status-line slice of observational-memory progress
(pending tokens vs. observation threshold, accumulated observations vs.
reflection threshold, plus projected message removal / reflection savings)tokenUsage— cumulative token usage for the current threadsettings— agent behavior settings (yolo,thinkingLevel,
notifications,smartEditing)
GET /agent-controller/:controllerId/sessions/:resourceId/threadsaccepts
an optionaltagsquery param (a JSON-encoded object). A single resourceId can
be shared across git worktrees of the same repo (the id is derived from the git
URL), so passingtagsscopes the list to threads matching every tag (e.g.
{ projectPath }for the working directory). Each returned thread now also
includes the scopingtagsit was stamped with at creation.The session event stream route (
.../stream) now enqueues raw event objects
and lets the server adapter handle SSE framing, fixing a double-framing bug
where events were wrapped twice (data: "data: {...}\n\n"\n\n) and could not be
parsed by clients.@mastra/client-jsgains the matching types and reads:AgentControllerOMProgressandAgentControllerSessionSettings, surfaced on
AgentControllerSessionState(omProgress,tokenUsage,settings)- a
display_state_changedevent inKnownAgentControllerEventcarrying the
status-line figures AgentControllerSession.listThreads()now accepts either a number
(back-compat) or{ limit?, tags? }
Example:
const session = client.getAgentController('code').session(resourceId); // Scope a worktree's thread list (and resumed session) to its own threads. await session.create({ tags: { projectPath: '/repo/worktree-a' } }); const threads = await session.listThreads({ tags: { projectPath: '/repo/worktree-a' } }); // Read the status-line figures and agent settings. const state = await session.state(); state.omProgress; // observational-memory progress state.tokenUsage; // cumulative token usage state.settings; // { yolo, thinkingLevel, notifications, smartEditing }
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal. -
Scope harness session creation with tags so sessions sharing a resourceId can (#18446)
each resume their own thread.harness.createSession()now accepts an optionaltagsrecord. The tags are
(a) seeded into the new session's state, (b) stamped onto every thread the
session creates (so thread listings can be filtered back to the session's
scope), and (c) used to filter initial thread selection: a thread is a resume
candidate only when its metadata matches every provided tag. Previously, initial
thread selection only consulted the
harness-globalinitialState.projectPath; on a multi-session server (where one
Harness serves many scopes) a session could resume the most recently updated
thread from a different scope that shared the resourceId. Using a generic tag
record (e.g.{ projectPath }) keeps room for future scoping dimensions without
further API changes.The
@mastra/client-jsHarnessSession.create()method accepts{ tags }, and
thePOST /harness/:id/sessionsroute accepts atagsbody field.// before: initial thread chosen by resourceId only const session = await harness.createSession({ resourceId, id, ownerId }); // after: initial thread scoped to this worktree via a tag const session = await harness.createSession({ resourceId, id, ownerId, tags: { projectPath: '/repo/worktree-a' }, });
Patch Changes
-
feat(playground): render ask_user tool as interactive question UI in Studio (#18374)
Adds an
AskUserBadgecomponent that renders suspendedask_usertool calls
as interactive prompts with clickable option buttons (single/multi-select) or
free-text input. The user's answer is sent asresumeDatathrough the existing
sendToolApprovalflow to properly resume the tool.Plumbing changes:
sendToolApprovalBodySchemanow accepts optionalresumeDataagent.sendToolApproval()passes customresumeDatawhen provided@mastra/client-jsand@mastra/reactexpose the new parameter
-
Fixed conditional workflows so that re-running or rehydrating a run (time travel) no longer leaves the wrong branch marked as active. When a paused or replayed run lands on a conditional, arms whose condition does not evaluate truthy are now correctly recorded as skipped instead of staying stuck in a running state. (#18228)
The server workflow and schedule run-status response schemas now include the
'skipped'status so they stay in sync with core'sWorkflowRunStatus.
@mastra/slack@1.5.0
Minor Changes
-
Added
waitUntilsupport for channels so background agent runs survive serverless responses. (#17832)Without
waitUntil, the runtime freezes the invocation as soon as the webhook response returns, killing the agent run mid-flight and leaving the user with no reply.Auto-detected (no config needed):
- Cloudflare Workers — reads
c.executionCtx.waitUntil - Netlify Functions — reads
c.env.context.waitUntil
Requires explicit config:
Vercel needs a
waitUntilfunction passed directly because it exposeswaitUntilvia AsyncLocalStorage, not the request context. AWS Lambda doesn't needwaitUntil— it waits for the event loop to drain naturally.import { waitUntil } from '@vercel/functions'; import { SlackProvider } from '@mastra/slack'; new SlackProvider({ waitUntil });
new Agent({ channels: { adapters: { slack: createSlackAdapter({ ... }) }, waitUntil, }, });
For runtimes where
waitUntillives on the request context but isn't covered by the default, passresolveWaitUntil: (c) => fn | undefinedinstead.new Agent({ channels: { adapters: { slack: createSlackAdapter({ ... }) }, resolveWaitUntil: c => c.var.runtime?.waitUntil, }, });
Resolution order:
waitUntil→resolveWaitUntil(c)→ core default. - Cloudflare Workers — reads
Patch Changes
- Normalize trailing slashes in the Slack provider
baseUrl. AbaseUrlwith a trailing slash (e.g.MASTRA_BASE_URL=https://example.com/) previously produced double-slash callback URLs likehttps://example.com//slack/oauth/callback, which broke the OAuth flow and webhook delivery. The trailing slash is now stripped, so callback URLs are always well-formed. (#18483)
@mastra/tanstack-start@0.2.1
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/temporal@0.2.2
Patch Changes
-
Rename the
Harnessclass toAgentControllerand its associatedHarness*types toAgentController*(e.g.HarnessConfig→AgentControllerConfig,HarnessMode→AgentControllerMode,HarnessEvent→AgentControllerEvent). (#18505)@mastra/core: A new canonical subpath@mastra/core/agent-controllerexports theAgentControllerclass plus theAgentController*types. The legacy@mastra/core/harnesssubpath remains available and re-exports the deprecatedHarness*aliases, so existingHarnessclass and type usage continues to work unchanged. New code should import from@mastra/core/agent-controller. OnMastra, the hosted-controller API is exposed under agent-controller names —getAgentController,getAgentControllerById,listAgentControllers, and theagentControllersconfig key — whilegetHarness/getHarnessById/listHarnessesand theharnessesconfig key remain as deprecated aliases.@mastra/server: The controller session API is now served exclusively under/agent-controller/...(withagent-controller:read/agent-controller:executepermissions). The legacy/harness/...routes andharness:*permissions have been removed. List responses use theagentControllerskey, session responses usecontrollerId, and path params use:controllerId.@mastra/client-js:AgentControllerandAgentControllerSessionare now the canonical resource classes, withMastraClient.getAgentController(id)/listAgentControllers()targeting the/agent-controllerroutes and reading the canonicalagentControllers/controllerIdresponse keys. The deprecatedgetHarness/listHarnessesmethods andHarness/HarnessSessionclasses have been removed. This is a breaking change for the recently released client.The
@mastra/corepeer dependency floor is raised to>=1.47.0-0so consumers must be on the release that introduces the canonical agent-controller surface. This applies to@mastra/server,@mastra/deployer, andmastra(CLI), and is propagated to the packages that depend on them: the deployers (@mastra/deployer-cloud,@mastra/deployer-cloudflare,@mastra/deployer-netlify,@mastra/deployer-vercel), the server adapters (@mastra/express,@mastra/fastify,@mastra/hono,@mastra/koa,@mastra/nestjs,@mastra/next,@mastra/tanstack-start), and@mastra/temporal.
@mastra/upstash@1.2.1
Patch Changes
- Fixed workflow runs preserving their original creation time when re-persisted in Upstash storage, including concurrent saves. (#18004)
@mastra/voyageai@0.3.0
Minor Changes
-
Added support for the
voyage-context-4contextualized chunk embedding model (preview). Each chunk is embedded with awareness of the other chunks in the same document, capturing both local detail and document-level context. Supports flexible output dimensions (256, 512, 1024, 2048). (#18413)import { voyage, voyageContextualizedEmbedding } from '@mastra/voyageai'; // Pre-configured model const result = await voyage.context4.doEmbed({ values: [['Paragraph 1 from doc 1...', 'Paragraph 2 from doc 1...'], ['Content from doc 2...']], inputType: 'document', }); // Or configure explicitly const model = voyageContextualizedEmbedding({ model: 'voyage-context-4', outputDimension: 512 });
Other updated packages
The following packages were updated with dependency changes only:
- @mastra/agent-builder@1.1.2
- @mastra/arize@1.3.2
- @mastra/arthur@0.4.2
- @mastra/braintrust@1.2.2
- @mastra/datadog@1.3.2
- @mastra/editor@0.13.2
- @mastra/laminar@1.3.2
- @mastra/langfuse@1.4.2
- @mastra/langsmith@1.3.2
- @mastra/longmemeval@1.1.2
- @mastra/mcp-docs-server@1.2.2
- @mastra/opencode@0.1.2
- @mastra/otel-exporter@1.3.2
- @mastra/posthog@1.1.2
- @mastra/sentry@1.2.2
- @mastra/voice-google-gemini-live@0.14.1
- @mastra/voice-openai-realtime@0.13.1
- @mastra/voice-xai-realtime@0.2.1