Highlights
End-user (per-resource) connections in @mastra/connect
tools({ resourceId }) and new userConnectRoutes() enable user-scoped OAuth connections so agents can safely use each end user’s accounts (in addition to global connections), with built-in caching and hard enforcement that one user’s connection can’t serve another user.
In-chat “request connection” prompts for missing integrations
Resource-scoped tool resolution now includes a built-in request_connection tool that returns a structured connect-prompt payload (provider list + connection state) so chat UIs can render a connect card when the agent needs an unconnected provider.
Span aggregation API + store support (ClickHouse/Postgres/DuckDB)
New POST /observability/spans/aggregate plus aggregateSpans() in ClickHouse/Postgres/DuckDB enable fast grouped metrics over spans (counts, latency, error rate, tokens, cost) for agent runs, tools, workflows, and more—powering richer Metrics/observability experiences.
Unified, persisted provider-error classification (better retries + better UX)
@mastra/core/error adds classifyProviderError (and related helpers) and server streams now carry provider status/body/requestId/modelId/codes/reason so clients can show consistent, actionable error messages live and after reload; retry logic (StreamErrorRetryProcessor) now aligns with the same classification.
Run status + durable execution control improvements
Thread subscriptions can opt into withRunStatus: true to receive ordered thread-run-status outcomes without closing the subscription, and clients can explicitly cancel durable runs via agent.abortRun(runId) (disconnecting observers no longer aborts durable/evented execution by default).
Breaking Changes
queryTraceThreads()thread rows no longer includemodelorprovider, andpage.limitis now capped at 100 (default 25); larger limits fail validation.@mastra/connectconnect-session creation response changed:POST /connect/:provider/sessionsnow returnslaunchUrl(server-side verified launch route) instead ofconnectUrl.@mastra/code-sdkno longer registers built-in subagents by default; you must passsubagents: [...builtinSubagents]to keep prior behavior.@mastra/playground-uiTracesExplorersorting API changed to a single{ field, direction }object (replacingsortDirection/onSortDirectionChange).
Changelog
@mastra/core@1.80.0
Minor Changes
-
Added
agentModeltodataset.startExperiment()anddataset.startExperimentAsync()so you can run an agent experiment against a different model without editing or versioning the agent. The model is passed with each call the experiment makes: the registered agent, its sub-agents and other experiments running at the same time keep their own models, and the agent version is picked the same way as withoutagentModel. (#28165)await dataset.startExperiment({ targetType: 'agent', targetId: 'support-agent', agentModel: 'anthropic/claude-haiku-5-5', scorers: ['accuracy'], });
The experiment's
metadata.agentModeland each run's trace metadata record the model (for exampleanthropic/claude-haiku-5-5), so runs on different models can be told apart.agentModelworks only with agent targets and is rejected before an experiment record is created otherwise. -
Channel
formatErrornow receives the failed run's request context as a second argument, so the message posted to Slack, Discord, Teams or Telegram can link back to whatever the run belongs to. Formatters that take only the error keep working. When a stream fails with a raw provider payload instead of anError, the error passed toformatErrorkeeps that payload as itscause, so the formatter can still tell what failed. (#27811)channels: { adapters: { slack: { adapter: createSlackAdapter(), formatError: (error, { requestContext }) => { const ticketId = requestContext?.get('ticketId'); return ticketId ? `❌ ${error.message} (ticket ${ticketId})` : `❌ ${error.message}`; }, }, }, },
-
Added
classifyProviderError,providerErrorReasonandtoPersistedErrorIdentityto@mastra/core/error: one reader for model-provider failures (authentication, quota, rate limit, context overflow, rejected model or request, timeout, outage) that takes HTTP status and provider codes before wording. A status from the GitHub API or a storage call is not mistaken for the model provider's.providerRequestIdandproviderModelIdreturn the provider's request id and the model the failed request named, also from a wrapped cause, andPROVIDER_CALL_ERROR_NAMEmatches the name of the AI SDK's provider call error. (#28496)Saved error parts now also keep every provider code as
codesand the provider'sreasonsentence, so a reloaded thread classifies like a live one, including a failure the provider reported mid-stream.toPersistedErrorIdentity(error)returns that saved shape, so anything that sends an error to a client can send the same one. Thereasoncomes from the provider's response, including a stringdetailfield and a response wrapped as another error's cause; any other cause stays out of thread history, and a long reason is cut at 2,000 characters.Each kind names a recovery action. New kinds can arrive in minor releases, and no kind is renamed or removed within 1.x, so keep a default branch when you switch on one:
import { classifyProviderError } from '@mastra/core/error'; switch (classifyProviderError(error)) { case 'rate_limited': // wait, then retry break; case 'quota': // ask for more credit break; default: // show the provider's reason }
-
@mastra/core/workspacenow exportsgetMimeType, the extension-based lookupLocalFilesystemuses, so custom filesystem providers can fill inFileStat.mimeTypethe same way. (#28302)import { getMimeType } from '@mastra/core/workspace'; getMimeType('page.png'); // 'image/png' getMimeType('notes.unknown'); // 'application/octet-stream'
-
Fixed stored span previews to preserve intentionally empty strings instead of replacing them with payload content. (#28442)
Added
buildSpanPreviews()to generate input, output, and error previews from a processed span. Support is advertised by theobservability-span-previewscore feature flag.import { buildSpanPreviews } from '@mastra/core/observability'; const previews = buildSpanPreviews(span);
-
Added render-only tools that stream display calls and let agents and sub-agents continue without a client result. Use
renderOnly: truewhen the browser only needs to show the call: (#28082)import { createTool } from '@mastra/core/tools'; import { z } from 'zod'; const showCard = createTool({ id: 'show-card', description: 'Display a product card', inputSchema: z.object({ productId: z.string() }), renderOnly: true, });
-
Span records now carry nine native fields in their own columns:
externalParentSpanId,resumedFromSpanId,model,provider,outcome,stopReason,stopReasonContext,timeToFirstTokenMsanderrorCount. Exported spans can supply them, the storage exporters copy them as given, and a field the span does not set is stored asnull. This release only adds the fields; later releases fill them in. (#28389) -
Added an opt-in
onMessagechannel handler for messages that do not mention the bot. CalldefaultHandlerto run the agent, post its reply, and subscribe the thread. Unmentioned messages stay ignored when the handler is omitted orfalse. (#28285)import type { ChannelHandlers } from '@mastra/core/channels'; const handlers: ChannelHandlers = { onMessage: async (thread, message, defaultHandler) => { if (thread.channelId !== 'slack:C_SUPPORT') return; await defaultHandler(thread, message); }, };
Runs started through
onMessagereportchannel.eventTypeasmessage. Existing event types are unchanged. When a queued batch mixes mentioned and unmentioned senders, unmentioned senders go toonMessageonly if it is set. Otherwise they still reachonMention, as before.Fixes #27060.
-
Added a
textDisplaychannel adapter option. SettextDisplay: 'hidden'to stop posting the agent's reply text, for example when the agent replies through a tool you give it. Tool display, approval prompts, errors and typing status still show, and the text still reaches the agent's stream and memory. (#28067)channels: { adapters: { slack: { adapter: createSlackAdapter(), textDisplay: 'hidden', }, }, },
-
Agent run spans now show the
modelandproviderthe run was configured with, on regular, durable and evented agents, including resumed runs. Model step spans gained the same two fields for the model each step actually called. (#28485) -
Added opt-in shared-channel tool approvals while keeping requester-only approval as the default. Configure
new SlackProvider({ toolApprovers: 'anyone' })to allow channel members to approve or deny pending tools. (#28542)Also in: @mastra/slack@1.8.0
-
Added
get(pid, { release: false })to the sandbox process manager. It reads a process without dismissing it once it has exited, so one reader can look at a finished command's output without taking it from another, such as the agent that started it. The default is unchanged. (#27919)// Show a finished command's output without dismissing it const handle = await sandbox.processes.get(pid, { release: false }); console.log(handle?.stdout);
-
Thread subscriptions now publish a pending user-message chunk when a steer is accepted, so subscribers can present the message before the agent reads it. (#28204)
Queued follow-ups publish queued user-message chunks when accepted and
data-user-message-cancelledchunks when cancelled. -
Added
AgentController.getDefaultMode(), which returns the mode new sessions start in. It followsdefaultModeId, then a mode marked as default, then the first mode, so you can read the starting model without creating a session. (#28402)const mode = controller.getDefaultMode(); console.log(mode.id, mode.defaultModelId);
-
Agent calls to OpenAI-compatible Chat Completions providers, including router models that resolve to a Chat Completions endpoint (such as
'groq/...'or a customurl), now send all leading system instructions as one system message. SettingerrorProcessorDefaults: falseturns this merge off. (#27626)processLLMRequestprocessors now receiveapiProviderId: the provider id of the model that will actually be called, for examplegroq.chatoropenai.responses, wheremodel.providerwould only saygroqoropenai.import type { Processor } from '@mastra/core/processors'; const chatOnlyRewrite: Processor = { id: 'chat-only-rewrite', processLLMRequest({ prompt, apiProviderId }) { if (!apiProviderId?.endsWith('.chat')) return; return { prompt: prompt.filter(message => message.role !== 'system' || message.content.trim() !== '') }; }, };
-
Added opt-in
withRunStatus: truefor thread subscriptions to emit orderedthread-run-statuschunks withsuccess,failed,aborted, orsuspendedoutcomes without closing the subscription. Reconnecting subscribers recover outcomes retained by the PubSub backend. Initial history includesactiveRunId, the run owning the thread during hydration, ornullwhen idle. (#28621)const subscription = await agent.subscribeToThread({ resourceId: 'user-123', threadId: 'thread-456', withRunStatus: true, }); for await (const chunk of subscription.stream) { if (chunk.type === 'thread-run-status') { console.log(chunk.runId, chunk.payload.status); } }
-
Removed
modelandproviderfrom thread rows returned byqueryThreads()with atimeRangerequest. A thread can contain many model calls, so a single model and provider was misleading, and looking them up made thread pages slow. (#28595)Thread pages now default to 25 rows and allow at most 100 (previously 100 and 1,000). Requests with a larger
page.limitnow fail validation. Usepage.nextto load further pages.Before
const { threads } = await client.queryTraceThreads({ timeRange: { traces: range }, page: { limit: 500 } }); threads[0].model; // "gpt-4o"
After
const { threads, page } = await client.queryTraceThreads({ timeRange: { traces: range }, page: { limit: 100 } }); // threads[0].model no longer exists; query the thread's spans for model usage const next = await client.queryTraceThreads({ timeRange: { traces: range }, page: { limit: 100, after: page.next! }, });
Patch Changes
-
Update provider registry and model documentation with latest models and providers (
c253e13) -
Fixed durable and evented agents dropping a background task's result when the task had been dispatched but no worker had picked it up yet. (#28228)
-
Fixed background tasks staying
runningforever when their background-task workflow run ended as failed before a terminal status was saved (for example, when the storage write that marks the task completed throws). (#27933) -
Fixed foreground command exceptions to include a failed exit code in the returned output. (#28406)
-
Fixed recovery of ToolSearchProcessor-loaded tools after a crash in an evented agent, with either
in-memoryorcontextstorage. (#28295) -
Fixed channel agents losing their channel instructions on runs that didn't start from a chat message, such as a schedule, a Studio prompt or a signal. (#28078)
-
Added a
ProviderHistoryCompatsafeguard that sends an assistant tool call whose stored input is missing ornullas{}on every provider, so a stored row without input can't make providers reject the replayed history. (#28332) -
Permission checks in server handlers now use the same provider as route-level checks. (#28543)
Also in: @mastra/server@1.80.0
-
Fixed token usage being reported as
undefinedinonFinishwhen a structured-output run fails schema validation. (#28671) -
Fixed
processInput()receivingagent: undefinedin every input processor after the first. (#28443) -
@mastra/core/channelsnow exportsCHAT_CHANNEL_RENDER_CONTEXT_KEYand theChatChannelRenderContexttype, so tools resolved per request can reach the live chat thread a run is replying in (for example, to upload a file into it). (#27351) -
Reject contained local filesystem reads and directory listings when a symlink swap is detected outside configured roots; preserve metadata access to unreadable files. (#28092)
-
Exported durable-agent helpers that
@mastra/inngestreuses instead of copying:applyReservedMemoryContextKeys,emitAbortEvent,createDurableIsTaskCompleteStepandcreateDurableGoalStepfrom@mastra/core/agent/durable, andcreateTimeoutAbortSignalfrom@mastra/core/loop. (#28232) -
StreamErrorRetryProcessornow decides retries with the shared provider-failure reader from@mastra/core/error, so it agrees with every other place Mastra reads a model-provider failure. (#28496) -
Signal contents now reach the model as written inside their tag. (#27150)
-
A saved error part of a failed provider call now keeps
modelId, the model the request named, so a reloaded thread can say which model failed. (#27811) -
Fixed
generate(),resumeStream(), andresumeGenerate()to reject invalidmodelSettings.timeoutvalues with the sameTypeError. (#28030) -
Fixed durable and evented agent streams dropping provider metadata from successful tool-result chunks, including sub-agent text output mappings, while preserving original tool-call metadata in payload-transform callbacks. (#28025)
-
Fixed
LocalFilesystemso writes through symlinked parent directories cannot create files or directories outside the workspace or allowed paths. (#28148) -
Durable agents now honor their configured
notifications.deliveryPolicy, and forked durable agents retain their Mastra instance so notification signals can be sent from forks. (#28639) -
Restore text streamed before tool approval in resumed durable and evented agent output. (#27582)
-
Fixed durable agent streams with
closeOnSuspend: trueclosing before they deliver their chunks when the agent uses Redis Streams PubSub. (#28504) -
Fixed
observe()on durable and evented agents throwingCannot read private member #optionswhen readingfullStream. (#28531) -
Restore the persisted delegation tool call on a cold durable-agent resume before updating suspension metadata. (#28050)
-
Fixed tool hooks passed to
agent.stream()andagent.generate()being ignored in durable and evented agents. (#27459) -
Fixed processor reminders sent after a durable or evented step returns being lost before the next model request. (#28154)
-
Allow server-owned HTTP observers of durable and evented
untilIdleruns to detach without aborting execution, including resumed streams. (#28162) -
Fixed cancelling an evented workflow run with workers on several replicas. (#28489)
-
Fixed evented workflows and evented agents hanging when a step exhausts its retries and publishing the
workflow.failevent briefly fails. (#28218) -
Fixed the evented workflow engine reporting a
foreachstep assuccesswhile its iterations were still running. (#27932) -
Fixed evented workflow runs that never finished after being cancelled from another Mastra instance (or after
startAsync()). (#28434) -
Fixed evented agents calling a throwing
stopWhenthree times. (#28215) -
Fixed durable and evented agents recording raw provider usage on model_step spans. (#28239)
-
Added optional model release dates to provider catalogs for newest-first model selection. (#27661)
Also in: @mastra/client-js@1.57.0, @mastra/factory@0.25.0, @mastra/server@1.80.0
-
Fixed orphaned tool results causing requests to fail when switching model providers after hosted tool calls. (#28286)
-
Corrected the
maxProcessorRetriesdoc comment on per-call agent options. (#28576) -
Keep recalled messages as memory references in durable-agent checkpoints when
messageHistory.maxTokensis set. (#28049) -
Fixed lost task updates when task tools run concurrently in the same thread. (#28294)
-
File-based agents can now save overrides without changing their source files, matching code-defined agents. (#28159)
-
Fixed background tasks cancelled from another process continuing to run. (#28523)
-
Fixed structured output results and validation errors arriving after the finish event, so idle-thread subscribers receive them before the run ends. (#28617)
-
Fixed removed messages coming back into the request when several input processors run in one step. (#28369)
-
Fixed
response.idbeing lost when a model provider (for example OpenRouter) streams response metadata across several partial events. (#26660) -
Fixed
add_reactionandremove_reactionfailing with "No channel context" on runs that did not start from a chat message, such as a schedule, a Studio prompt or a woken run. (#28073) -
Fixed missing token usage in streamed responses from Kimi coding-plan models. (#28537)
-
Fixed evented agent runs with Postgres storage that hung when a worker process stopped. (#28054)
-
Fixed a run that lost its thread lease cutting off the step it was in the middle of: a model response still streaming, or a tool call such as a long command. (#28359)
-
Fixed an unhandled rejection when a run lost its thread lease and its agent could not abort the run. (#28344)
-
Record a
tool_callspan for tool calls served by experimenttoolMocks. (#27954) -
Fixed messages sent from another process to a busy agent thread waiting until the current run ended. (#28298)
-
Fixed servers staying busy forever after using deferred notifications. (#28550)
-
Exported
readNotificationRoutingRequirementfrom@mastra/core/notifications, so a notification delivery policy can tell whether a notification was routed to the thread's claimed owner. (#28066) -
Fixed a call that passes
hooks: { beforeToolCall: null }(for example from a JSON request body) turning off the agent's own tool hooks. (#27459) -
Fixed
observe(runId, { offset })replaying the whole run when the offset is at or past the end of the run's log on a transport that keeps old messages, such as Redis Streams. (#28348) -
You can now choose which attachment types the Observational Memory Observer receives:
observation.observeAttachmentsaccepts a MIME type allowlist (string[]) in the public types, matching the runtime (images and PDFs by default). (#28556) -
Keep the current user request and delayed tool results in the prompt when a durable Observational Memory turn resumes on another worker. (#28045)
Also in: @mastra/memory@1.39.1
-
Fixed tool calls and nested workflows in durable agent runs losing their request context metadata. (#28118)
Also in: @mastra/inngest@1.10.8, @mastra/observability@1.22.0
-
Fixed a TypeScript error when passing steps to
.parallel()whoseinputSchemaonly uses part of the previous step's output. (#28225) -
Fixed thread peer discovery reporting live peers as absent when the caller was busy right after asking. (#28098)
-
Fixed processor hooks receiving
args.agentasundefinedduring regular, durable and evented agent runs. (#28463) -
Fixed missing provider details on failed model calls. (#27906)
-
Fixed durable and evented onFinish tool results to use the same chunk shape as the default engine, including per-step results. (#28145)
-
Added a
neonfilesystem icon so Neon Object Storage mounts show their own icon in the Studio file tree. (#28032)Also in: @mastra/playground-ui@66.0.0
-
Log claimed schedule occurrences and accepted publications with their schedule ID, run ID, and scheduled fire time. (#28544)
-
Fixed Claude 5.x thinking blocks being stripped from earlier assistant messages on every request, which changed the prompt prefix each step and broke Anthropic prompt caching. (#28552)
-
Fixed agent runs that reported an API error instead of an abort when the run was cancelled while an error processor was still handling that error. (#28158)
-
Fixed
DurableAgent.recover()reporting an initial pending snapshot without workflow input as corrupt. (#28611) -
The traces list Input column now previews an agent run started by a signal by its contents, instead of the signal as JSON. (#28038)
-
Output processors can now add text to an agent's response when observational memory is enabled and the final step is empty after a tool call. (#28046)
-
Fixed
read_filereturning only metadata for.jsonl,.phpand.dartfiles. (#28462) -
Added optional
batchUpdateUnendedSpans()to observability storage. (#28147) -
Fixed default workflow runs continuing to later steps and overwriting their status with success after another process canceled the run through shared storage. (#27904)
-
Fixed threads becoming unusable after a model sent a tool call with arguments that could not be parsed. (#28099)
-
Fixed
run.restart()re-running work that had already finished when a workflow crashed inside a parallel block or a.foreach(). (#27935) -
Fixed resumed agent runs disappearing from storage before their final messages are saved. (#28157)
-
Fixed runs being aborted when their thread lease lapsed only because their process fell behind. (#28079)
-
Fixed
observe()sending duplicate frames, and made a run's cached frames exactly what it replays. (#27352) -
Fixed tool search so complete tool names in a query rank before keyword matches, including names with hyphens and underscores. (#28141)
-
Scheduler now retries a failed workflow or agent schedule dispatch up to three times before recording it as failed. (#28525)
-
Improved the scheduler so it no longer queries storage every 10 seconds when nothing is due. (#28550)
-
Fixed channel messages and tool approval actions bypassing durable execution on durable and evented agents, including channels attached after construction. (#27944)
-
Fixed
mapUserToResourceIdbeing ignored when defined as a method on aMastraAuthProvidersubclass. (#28297) -
Fixed
onFinish.textincluding replies rejected byprocessOutputStepguardrails, including discarded retry attempts on durable agents. (#28029) -
Fixed canceled runs that hang on tools that ignore cancellation. (#28472)
-
Fixed
mastra.shutdown()crashing the process with an unhandled rejection when background tasks were still active. (#28509) -
Studio session cookies are now host-only, so a session is never sent to other deployments on a shared domain. (#28168)
Also in: @mastra/auth-studio@1.3.11, @mastra/factory@0.25.0, @mastra/server@1.80.0
-
You can now filter and group spans by their parent or root entity, for example to count tool calls per agent or per workflow. (#28047)
Also in: @mastra/observability@1.22.0
-
Fixed channel agents calling a missing
add_reactiontool. (#28067) -
Fixed a run being stopped as if another run had taken its thread when its process stalled past the thread lease duration while a lease renewal was in flight. (#28316)
-
Fixed tool calls reported inconsistently in
onStepFinishandonFinishsteps. (#28471) -
Fixed agent streams dropping chunks when a run fails while the reader is behind. (#28227)
-
Fixed evented foreach steps keeping a
suspendedAttimestamp after the step successfully resumed and finished. (#28151) -
Fixed
getFullOutput().textdropping text from the step in progress when a run suspends for tool approval or a tool suspension after an earlier step has completed. (#28351) -
Fixed durable and evented streams dropping the suspending step's token usage. (#27882)
-
Fixed spans, logs, metrics, scores and feedback reporting another entity's version. (#28423)
Also in: @mastra/observability@1.22.0
-
Fixed durable and evented agents running tools with empty arguments when the model returned malformed JSON. (#28332)
-
Thread lease-loss and cross-instance stop handling now skip
abortRunStreamwhen a run record's agent object does not implement it, instead of raising an unhandledabortRunStream is not a functionrejection. (#28469) -
Fixed agent thread streams that misreported a run's state when pubsub events were missing. (#27928)
-
Fixed trace scoring for agent scorers: tool calls that start in the same millisecond (parallel tool calls) now keep their original order, and tools executed by the model provider (for example Anthropic web search) are now included in the scorer's tool invocations, matching what live scoring sees. (#27953)
-
Fixed
context.observebeing undefined when a tool is called directly withtool.execute(input, { requestContext })or run as a workflow step viacreateStep(tool). (#28579) -
Fixed resuming a suspended durable or evented agent with
resumeStreamUntilIdle()(orresumeStream(..., { untilIdle: true })). (#28301) -
Fixed background tasks failing with "authenticated user is required" when fine-grained authorization is configured. (#28506)
-
Fixed total run deadlines not terminating durable and evented agent runs when a tool ignores cancellation. (#27941)
-
Progress events from tools used with
createStep(tool)now reach workflow and agent streams by forwarding the step writer. (#28615) -
Fixed agents saying they can't save information when working memory uses
agentManaged: false. (#28441)Also in: @mastra/memory@1.39.1
@mastra/agent-builder@1.1.31
Patch Changes
-
Observational memory now detects context-overflow errors with the shared provider error reader from @mastra/core, so it recovers from the same overflow shapes the rest of Mastra recognizes, including overflow named only in a provider's response body or stream error frame. (#28496)
Also in: @mastra/editor@0.16.5, @mastra/memory@1.39.1
@mastra/agentfs@0.2.3
Patch Changes
-
Fixed
read_filereturning images and PDFs from E2B, platform, AgentFS, Modal and Mesa filesystems as garbled text. (#28462)Also in: @mastra/e2b@0.15.1, @mastra/e2b-desktop@0.1.10, @mastra/mesa@0.3.3, @mastra/modal@0.7.3, @mastra/platform-workspace@1.10.0
@mastra/browser-firecrawl@0.2.5
Patch Changes
- Limited the
agent-browserpeer dependency to>=0.19.0 <0.20.0. (#28116)
@mastra/clickhouse@1.27.0
Minor Changes
-
Added
aggregateSpans()to the ClickHouse observability store. It groups and measures the spansquerySpans()returns (counts, durations, error rates, tokens, cost), attributes token and cost usage to the span that recorded it, and reports thespan-aggregatefeature. Filters on agent runs, workflow runs, tool calls, and other branch span types read only those spans, so they stay fast over long windows. (#27857) -
Spans now store nine native fields in their own columns:
externalParentSpanId,resumedFromSpanId,model,provider,outcome,stopReason,stopReasonContext,timeToFirstTokenMsanderrorCount. Existing databases get the columns automatically when the store starts. The columns stay empty for spans written before the upgrade, with an older@mastra/core, or by producers that do not set them yet. (#28389)Also in: @mastra/duckdb@1.16.0, @mastra/pg@1.33.0
Patch Changes
-
Fixed
aggregateTraces()cost measures dropping partly priced model calls. (#27881)Also in: @mastra/duckdb@1.16.0, @mastra/pg@1.33.0
-
Thread rows from
queryThreads()no longer includemodelorprovider, and the store no longer runs the per-page model lookup, so thread pages load faster. (#28595)Also in: @mastra/duckdb@1.16.0, @mastra/pg@1.33.0
@mastra/client-js@1.57.0
Minor Changes
-
Added
agentModeltotriggerDatasetExperiment()to run an agent experiment against a different model. (#28165)await client.triggerDatasetExperiment({ datasetId: 'dataset-1', targetType: 'agent', targetId: 'support-agent', agentModel: { provider: 'anthropic', modelId: 'claude-haiku-5-5' }, });
-
Added
withRunStatus: trueto thread subscriptions to receive retained and livethread-run-statusoutcomes. Callback types include run statuses only when requested. (#28621)const subscription = await agent.subscribeToThread({ resourceId: 'user-123', threadId: 'thread-456', withRunStatus: true, }); await subscription.processDataStream({ onChunk: chunk => { if (chunk.type === 'thread-run-status') console.log(chunk.runId, chunk.payload.status); }, });
-
Add
agent.abortRun(runId)to explicitly cancel durable execution without requiring a memory thread. (#28162)const runId = crypto.randomUUID(); await agent.stream('Start the task', { runId }); await agent.abortRun(runId);
-
Added
aggregateSpans()for grouped span measures, such as agent-run counts by status per day, including nested agent runs. (#27827)const { capabilities } = await client.getObservabilityCapabilities(); if (capabilities.spanAggregate) { const { rows } = await client.aggregateSpans({ timeRange: { from: '2026-10-01T00:00:00Z', to: '2026-10-08T00:00:00Z' }, where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'agent_run' } }, groupBy: ['status'], interval: '1d', measures: ['count'], }); }
Patch Changes
-
Added an optional
displayState: falsesetting to AgentController session subscriptions. (#28527)Also in: @mastra/server@1.80.0
-
aggregateTraces()now accepts an optional abort signal, so callers can cancel an aggregation that is no longer needed: (#27908) -
Removed
modelandproviderfrom the thread rows type returned byqueryTraceThreads(). (#28595) -
Fixed streamed client tool results to include their original arguments. (#28119)
-
Span types returned by the trace and span endpoints now include the native
externalParentSpanId,resumedFromSpanId,model,provider,outcome,stopReason,stopReasonContext,timeToFirstTokenMsanderrorCountfields. (#28389) -
Fix per-call
abortSignalcancellation so it stops durable runs when streaming, resuming, or approving or declining tool calls. (#28162) -
Fixed slow parsing of large streamed events in @mastra/client-js. (#28282)
@mastra/cloudflare-d1@1.4.5
Patch Changes
-
Fixed workflow runs canceled from another process being overwritten by a concurrent snapshot write. (#27904)
Also in: @mastra/dsql@1.5.5, @mastra/libsql@1.27.1, @mastra/mssql@1.10.6, @mastra/mysql@0.14.1, @mastra/pg@1.33.0
-
Added
"license": "Apache-2.0"topackage.jsonso the published npm metadata reports the correct SPDX license instead of "Unlicensed". (#28122)Also in: @mastra/couchbase@1.1.4, @mastra/dynamodb@1.4.5, @mastra/editor@0.16.5, @mastra/elasticsearch@1.4.6, @mastra/google-cloud-pubsub@1.1.5, @mastra/inngest@1.10.8, @mastra/lance@1.5.2, @mastra/mongodb@1.24.1, @mastra/opensearch@1.1.4, @mastra/redis-streams@0.7.0, @mastra/valkey-streams@0.5.7
@mastra/code-sdk@1.16.0
Minor Changes
-
Mastra Code no longer registers subagents unless you turn them on.
createMastraCode()andmountAgentControllerOnMastra()now defaultsubagentsto an empty list. (#28600)Before, omitting
subagentsregistered the explore, plan and execute subagents:await createMastraCode();
After, pass
builtinSubagentsto keep them:import { builtinSubagents, createMastraCode } from '@mastra/code-sdk'; await createMastraCode({ subagents: [...builtinSubagents] });
The same applies to
mountAgentControllerOnMastra().The TUI, headless
mastracode --promptruns and ACP sessions all read thesubagentsEnabledsetting (toggled with/subagents, off by default), so subagents only run when a user opts in.
Patch Changes
-
Fixed tool calls on Amazon Bedrock models failing with
AI_TypeValidationErrorwhen zod 4.4 or newer is installed. (#28515) -
Use
claude-sonnet-5-5for Claude Max calls without a model ID, replacing the retiredclaude-sonnet-4-20250514default. (#28094) -
An exhausted provider quota now shows its own error and a hint to check the account's billing or usage allowance, instead of being reported as a rate limit with "Wait a moment and try again". (#28496)
-
Restored the per-module
distlayout so every source module is published as its own file again. (#28139)Also in: @mastra/factory@0.25.0
-
The missing provider credential error now names the model that needed the credential, so you can tell which setting asked for the provider. (#28179)
-
Fixed Outcome scoring so build and test results recognize successful and failed execute_command commands, and regression scoring detects failures after a prior pass. (#28406)
-
Fixed saved thread-scope observation thresholds at or below 2,000 tokens stopping observational memory from starting. (#27450)
-
Fixed duplicate Core installations when embedding the Code SDK by requiring applications to provide @mastra/core 1.80 or later. (#28419)
-
Fixed notifications failing with "No model available: this run started without a controller session context" when several Mastra Code processes share one database and one of them was created with its own
pubsub. (#28031) -
Fixed a notification sent from one Mastra Code process to a thread that another process on the same resource runs. (#28066)
-
Kept OpenAI prompt caching working across the steps of a run. OpenAI requests now send the thread id as
prompt_cache_key, on both the ChatGPT subscription (Codex) and API-key routes. (#28374) -
Fixed
read_filereturning images and PDFs as text when the workspace usesSandboxFilesystem. (#28302) -
Subscription providers (Anthropic, OpenAI Codex, GitHub Copilot, xAI, Kimi For Coding) now say " sign-in expired." when a saved sign-in can no longer be renewed, matching the Sign-in expired status in Settings. (#28401)
@mastra/connect@1.2.0
Minor Changes
-
In-chat connect prompts for end-user connections. Resource-scoped
tools({ resourceId })resolutions now include a built-inrequest_connectiontool: when a task needs a provider the user hasn't connected, the agent calls it and gets a structuredconnect-promptpayload listing connectable providers with their current connection state, which chat UIs render as a connect card. The connectable set follows theprovidersallowlist when one is set, otherwise the full catalog. The tool is never added to global-only resolutions. (#26928)import { tools } from '@mastra/connect'; export const agent = new Agent({ // ... tools: ctx => tools({ resourceId: ctx.requestContext.get('mastra__resourceId') }), }); // Opt out of the built-in tool: tools({ resourceId: userId, connectPrompt: false });
userConnectRoutes()providersis now optional: omit it to expose the full platform catalog on the end-user connect surface. An explicit empty array is still rejected, and configuring an allowlist behaves exactly as before.// All catalog providers are connectable: userConnectRoutes(); // Or restrict to an allowlist, as before: userConnectRoutes({ providers: ['linear', 'slack'] });
-
Added end-user (per-resource) connections to @mastra/connect. (#26928)
Scope tools to an end user
tools()accepts a newresourceIdoption — a static key or a callback derived per request — so an agent resolves the shared global connections plus that end user's own connections. Every platform call made under a resource scope asserts the key, so one user's connection can never serve another user's request.import { tools } from '@mastra/connect'; // Per-request scoping on an agent: new Agent({ tools: ctx => tools({ resourceId: myUserIdFrom(ctx) }) }); // Static/global usage is unchanged: new Agent({ tools: tools({ providers: ['linear'] }) });
Calling
tools()per request is cheap: identical options share one internal snapshot/MCP-client state, with per-resource caching and eviction. The returned resolver is also awaitable, so a dynamictoolsargument can return it directly.Let end users connect their own accounts
A new
userConnectRoutes()export returns mountable API routes (provider catalog, the caller's connections, connect sessions, status polling, disconnect, and a hosted connect page) gated on the authenticated end user's resource key fromserver.auth.mapUserToResourceId.import { Mastra } from '@mastra/core'; import { userConnectRoutes } from '@mastra/connect'; export const mastra = new Mastra({ server: { auth: { authenticateToken: async token => verifyToken(token), mapUserToResourceId: user => user.id, }, apiRoutes: [...userConnectRoutes({ providers: ['linear', 'slack'] })], }, });
credential()also gains an optionalresourceIdoption for asserting a resource-scoped connection's key. -
Added a Microsoft PowerPoint toolset with 18 tools for drive discovery, presentation creation, listing, retrieval, copying, moving, updating, deletion, sharing, versions, thumbnails, and content export. (#26285)
import { tools } from '@mastra/connect'; const powerpointTools = await tools({ providers: ['microsoft-powerpoint'] })(); const drive = await powerpointTools.microsoft_powerpoint_get_user_drive.execute({}); const presentations = await powerpointTools.microsoft_powerpoint_list_presentations.execute({ drive_id: drive.id });
-
Added a OneDrive toolset with 20 tools for drive discovery, folder and file management, uploads, downloads, copying, moving, sharing, and permissions. (#26287)
import { Agent } from '@mastra/core/agent'; import { tools } from '@mastra/connect'; const driveAgent = new Agent({ id: 'drive-agent', name: 'Drive agent', instructions: 'Use the connected OneDrive tools to manage files and folders.', model: 'openai/gpt-5-mini', tools: tools({ providers: ['one-drive'] }), });
-
Added project-managed provider policies for end-user connections. When
providersis omitted,userConnectRoutes()and the built-inrequest_connectiontool now use the project provider list from Mastra Platform. An explicit code allowlist still takes priority. (#26928)// Use the project policy from Mastra Platform. userConnectRoutes({}); // Or enforce a code-level override. userConnectRoutes({ providers: ['linear', 'slack'] });
Patch Changes
-
Gate end-user connect flows behind a launch route. (#26928)
-
Fixed provider generation to discover template aliases exposed as symlinks. (#27314)
-
Fixed delegated Microsoft Office provider generation to use the connected user's OneDrive and preserve supported generic proxy, typed request, and random UUID template patterns. (#27314)
@mastra/couchbase@1.1.4
Patch Changes
- Support deleting multiple Couchbase vectors by ID with
deleteVectors(). (#28614)
@mastra/deployer@1.80.0
Patch Changes
-
Fixed compatibility by requiring @mastra/core 1.80.0 or newer. (#28496)
Also in: @mastra/deployer-cloud@1.80.0, @mastra/deployer-cloudflare@1.2.39, @mastra/deployer-netlify@1.2.39, @mastra/deployer-sandbox@0.3.24, @mastra/deployer-vercel@1.2.39, @mastra/elysia@0.1.20, @mastra/express@1.5.24, @mastra/fastify@1.5.24, @mastra/hono@1.7.22, @mastra/koa@1.7.24, @mastra/nestjs@0.2.39, @mastra/next@0.2.38, @mastra/tanstack-start@0.2.38, @mastra/temporal@0.4.18
-
Fixed
mastra buildso tsconfigpathsimports of files with dots in their names are bundled, such asimport { repo } from 'src/repositories/user-repository.interface'. (#28439) -
Fixed
mastra buildfor apps at the root of a pnpm workspace on Linux. (#28248) -
Aligned the
rollupversion withmastraso the CLI builds against a singlerolluptype definition. (#28139) -
Fixed workspace resolution when the Mastra app is the workspace root package. (#28106)
@mastra/deployer-cloudflare@1.2.39
Patch Changes
-
Aligned the
rollupversion with@mastra/deployerso bundler plugins share a singlerolluptype definition. (#28139)Also in: @mastra/deployer-netlify@1.2.39, @mastra/temporal@0.4.18
-
Fixed agent streaming in Cloudflare Workers by updating the default compatibility date from
2025-04-01to2025-05-05, enabling WeakRef and FinalizationRegistry. (#28146)
@mastra/dsql@1.5.5
Patch Changes
- Fix
listMessagesdate-range filtering to honor exclusive start and end boundaries. (#28529)
@mastra/duckdb@1.16.0
Minor Changes
-
Added
aggregateSpans()to the DuckDB observability store, soPOST /observability/spans/aggregateworks with DuckDB. The store now reports thespan-aggregatefeature. (#27841)DuckDB now stores each span's parent and root entity (type, ID, name), and
querySpans()returns them and the span's execution source instead ofnull. Spans written before this change keepnullfor the parent and root entity fields.
Patch Changes
-
DuckDB now reports that it supports span aggregation. (#28326)
-
Fixed
aggregateTraces()on DuckDB failing with a Binder Error when grouping byexecutionSourceor counting distinctexecutionSourcevalues. (#28016)
@mastra/dynamodb@1.4.5
Patch Changes
- Fixed workflow and durable agent resumes that could fail or lose state when a different process resumed a run soon after it suspended. (#28182)
@mastra/e2b@0.15.1
Patch Changes
-
Updated the default E2B template to Node.js 24.22.1 for the October 2026 security fixes. (#28170)
-
Fixed background processes losing output, and
wait()failing, when a command wrote output as soon as it started. (#28056)Also in: @mastra/platform-workspace@1.10.0
-
sandbox.processes.list()now also returns exited processes whose output hasn't been read yet, with their exit code, so a finished command stays visible until it is read. (#27919)
@mastra/editor@0.16.5
Patch Changes
- Fixed editing file-based agents (agents defined in an
agents/<name>/folder) in Studio. (#28159)
@mastra/elysia@0.1.20
Patch Changes
-
Fixed an authorization bypass on custom API routes that use FGA. (#28203)
Also in: @mastra/express@1.5.24, @mastra/fastify@1.5.24, @mastra/hono@1.7.22, @mastra/koa@1.7.24
-
Custom routes registered with
registerApiRoutenow keep the status and message of anHTTPExceptionthey throw, on every server adapter (Hono, Express, Fastify, Koa, Elysia and NestJS). (#28216)Also in: @mastra/express@1.5.24, @mastra/fastify@1.5.24, @mastra/hono@1.7.22, @mastra/koa@1.7.24, @mastra/nestjs@0.2.39, @mastra/server@1.80.0
-
Fixed dataset schema updates showing "0 items fail validation" in Studio on Express, Fastify, Koa, Elysia and NestJS servers. (#28202)
Also in: @mastra/express@1.5.24, @mastra/fastify@1.5.24, @mastra/hono@1.7.22, @mastra/koa@1.7.24, @mastra/nestjs@0.2.39, @mastra/server@1.80.0
-
Fixed a spurious "Error in stream processing" log on Elysia when a client disconnects from an agent stream. (#28210)
-
Fixed the Elysia adapter's body size limit for streamed requests. (#28200)
-
Fixed MCP tool calls continuing to run after the client disconnects on the Hono, Elysia and Next adapters. (#28217)
Also in: @mastra/hono@1.7.22, @mastra/next@0.2.38, @mastra/server@1.80.0
-
The Elysia adapter now reads user permissions from the
mastra__userPermissionsrequest-context key, matching the Hono, Express, Fastify and Koa adapters. (#28543) -
Fixed route permission checks being skipped for Studio requests on the Express and Elysia adapters when RBAC is configured only under
studio. (#28199)Also in: @mastra/express@1.5.24, @mastra/server@1.80.0
@mastra/express@1.5.24
Patch Changes
- Fixed the Express adapter's body size limit for
multipart/form-datarequests sent without aContent-Lengthheader (chunked uploads). (#28209)
@mastra/factory@0.25.0
Minor Changes
-
Added Slack Socket Mode support to Factory integrations, including transport-specific credential validation and clean connection shutdown. (#28449)
new SlackIntegration({ mode: 'socket', appToken: process.env.SLACK_APP_TOKEN!, botToken: process.env.SLACK_APP_BOT_TOKEN!, });
-
Added a
reply_in_threadtool so a session's agent chooses what it posts to Slack, instead of every bit of reply text landing in the thread. The agent posts a short note when it starts a longer job, asks when it needs an answer, and posts the outcome when it finishes. To stay quiet, it doesn't post. (#28071)- Replies stream into the thread as the agent writes them, with "is typing..." while they start.
- After five minutes without posting, the agent gets one reminder to post a short status if it would help.
- When you prompt a Slack-linked session from the web UI, or it wakes up on its own, the agent posts only the outcome to the thread. It does that when people there asked for the work or are waiting on it.
To post the agent's full reply text again:
new SlackIntegration({ signingSecret, adapterOptions: { textDisplay: 'show' } });
-
Added
@bot muteand@bot unmutefor Slack threads. A muted bot ignores messages that don't tag it until someone tags it withunmute. It confirms either change with a reaction instead of a reply. Only people who can prompt the session can mute or unmute it. (#28071) -
Made the Factory MCP server work with Claude's custom connectors and browser MCP clients, and added experimental activity events. (#28019)
Works with Claude and browser clients. Browser-based MCP clients can now call the endpoint and read its sign-in challenge. The server tells clients what a Factory is and which tools to start with.
/web/config/featuresnow reportsmcp: truewhen the Factory serves its MCP endpoint.Follow Factory activity (experimental). MCP clients can poll a
factory.activityevent to see work item and session activity. Pass aworkItemIdoractionsto narrow it. Work item activity always shows up. When it happened in another member's private session it is markedprivateSession: truewithout naming the session, and activity on that session alone is left out. Events are delivered by polling only, so Claude and ChatGPT don't use it yet.{ "method": "events/poll", "params": { "name": "factory.activity", "arguments": { "workItemId": "<id>" }, "cursor": null } }Start with
cursor: nulland pass back the returnedcursoron each poll.The endpoint speaks MCP 2026-07-28, and also serves clients that still open with
initialize(such as VS Code and Cursor) statelessly. -
When Platform credentials are set and you don't pass a
sandbox,MastraFactorynow picks one for you. Undermastra devit runs sessions in aLocalFactorySandbox, so development no longer starts remote machines. Built deployments get aPlatformFactorySandbox. Asandboxyou pass still takes precedence. (#28400)LocalFactorySandboxoptions are now optional.rootdefaults toMASTRACODE_LOCAL_SANDBOX_ROOT, or~/.mastracode/web/sandboxeswhen that is unset.envdefaults to an allow-list of host variables, so git and TLS keep working while app secrets stay out of repository commands.// Before: the host wired the Platform sandbox itself new MastraFactory({ sandbox: new PlatformFactorySandbox() }); // After: omit it; local under `mastra dev`, Platform when built new MastraFactory({});
-
Added
processorstoFactoryIntegration. An integration can now add input and output processors to every session run, alongside its tools. They run before Factory's own processors, in the order integrations are listed.initialize()now also receives the controller's chat channels. (#28187)class MyIntegration implements FactoryIntegration { readonly id = 'my-integration'; readonly processors = { input: [new MyInputProcessor()], output: [new MyOutputProcessor()] }; routes() { return []; } }
-
Added a thinking level to your personal defaults. In Settings → Models, the Personal defaults and Factory defaults cards now pair each model picker with its thinking level, replacing the separate Thinking row. Chats on your personal defaults start at your personal level, or at the Factory level when you have not set one. Sessions and work-item runs on the Factory defaults keep the Factory level. The composer thinking control now says which default a session follows: Personal default or Factory default. (#28250)
-
Added a way to take over a teammate's shared session. Anyone steering someone else's shared session sees a Take ownership button on the line under the composer. It asks for confirmation first, then stops a running agent and hands the session over: their next message runs with their credentials, and the thread shows a "Damien took ownership" divider that the agent also reads. (#27957)
POST /web/user-sessions/:sessionId/owner { "expectedOwnerId": "user-ward" }
expectedOwnerIdis the owner the caller last saw. The response is{ session }with the new owner. The request returns409when someone else took the session first, when the caller already has a session on that branch, or for a Slack thread, Factory run or side session, which keep their owner, and404for a session the caller can't open. Each transfer is recorded in the Factory audit log asfactory.session.owner_transferred.
Patch Changes
-
Fixed guidance for replacing the default Factory boards and their plan-result rules. (#28093)
-
Chats on personal defaults no longer borrow from the Factory defaults. (#28402)
-
The Factory activity summary now loads only the events it shows, through a new
actionsfilter on the project audit route. (#28394) -
When a session linked to a Slack thread opens a pull request, its link is posted into the thread, and again when it merges. (#28311)
-
Sandbox: A Factory session's agent can now replace its own sandbox when it stops responding, with the new
factory_recreate_sandboxtool. (#28052) -
The Take ownership confirmation now says who pays once the session is yours. (#28023)
-
The Studio and Factory chat composers now show one button while an agent is running: Stop until the draft has something to send, then Send. (#28263)
-
Factory startup avoids loading GitHub, GitLab, Jira, Linear, and incident.io when these integrations are not in use. (#28254)
-
The Docker sandbox setting and its low-memory warning no longer name the underlying sandbox provider. (#28646)
Also in: @mastra/platform-workspace@1.10.0
-
Fixed chats in a Factory using the Factory's observational memory settings instead of their owner's. (#28179)
-
Factory tools now return a web link (
url) for work items and sessions, and channel agents link Factory items the same way they link pull requests. (#28630) -
Fixed the repository list the agent sees in a multi-repository Factory session. (#28327)
-
Discover open GitLab merge requests and issues when linking a repository or listing its items, so missing Review cards can appear without an initial webhook delivery. (#28518)
-
Factory now allows Mastra Platform sign-in on
*.localhosthosts (for examplemy-branch.factory.localhost), not only onlocalhostitself. (#27477) -
The web error card now names an outage that a provider reports mid-stream with its own code, such as a Codex
server_error, instead of showing Run stopped, live and after a reload. (#28496) -
Failed runs now say what went wrong and link to the fix, in the web chat and in Slack, instead of showing SDK error names such as
AI_APICallErrorwithBad Request. (#27811) -
Failed run reports now quote the model provider's own reason for any provider failure, not only usage limits. (#28496)
-
Added the session's history to the Factory sidebar hover card, in place of its branch names. (#28127)
-
Factory settings are grouped by topic: Account (My account, Preferences, Connections), Agent (Models, Memory, Skills, Behavior) and Factory (Repositories, Environment, Work Intake, Manage Factory). (#28100)
-
Channel-backed runs (Slack) get an
attach_filetool that uploads a file from the session workspace — a report, export, or image the agent produced — straight into the thread it is replying in, instead of pointing the sender at a sandbox path. (#27351) -
Reworked the top of the Factory sidebar. (#28271)
-
Added repository-boundary rules to the Factory review, re-review, self-review, GitLab review, triage, and planning skills. (#28497)
-
Traces and memory now show the skill that started a Factory run, instead of recording the kickoff as a message a person typed. (#27150)
-
Changed the Factory Changes panel to show every changed file's diff in one scroll, the way a pull request does. (#28274)
-
Reorganized Factory Settings so each setting has one home and every page uses the same rows, drawers, and connection flows. (#28602)
-
Fixed custom Factory skills being ignored in deployed build output. (#28142)
-
Fixed Open in Slack on Slack cards and their sessions. (#28136)
-
Collapsing the Factory sidebar now gives the page the whole window. (#28300)
-
Fixed saving intake settings resetting the selections of custom Factory integrations. (#28567)
-
Fixed Factory runs failing when repositories share an issue or pull request number. (#28152)
-
Fixed the session access checks skipping multipart form requests. (#28061)
-
Let Factory agents look up the models available to a session before choosing an exact model ID from a user's request to switch models. (#28055)
-
The memory settings preview now shows the Auto memory model a run will actually use, instead of one that needs a credential the run cannot reach. (#27450)
-
In the Factory web UI, a Slack reply the agent posts with
reply_in_threadnow shows as the message itself, rendered as markdown with its own footer (model, "Sent to Slack", copy, time), instead of a JSON tool card. (#28074) -
Made Factory's triage comment on GitHub easier to scan. (#28512)
-
Added support for scoped Jira API tokens by allowing API requests to use a separate Atlassian gateway URL while issue links keep using the Jira site URL. (#28569)
-
When a shared session stops because the owner's provider sign-in is missing or expired, a teammate steering it now sees who has to reconnect (for example "Ward Peeters needs to reconnect") instead of a Login link to their own settings, which could not fix it. (#28058)
-
Review: Factory's GitHub review agent now updates its own earlier review and test report on a pull request when it can, instead of posting new ones on every pass, so pull requests no longer fill up with stale Factory reviews. (#28330)
-
Removed the Factory Activity page, its Codebase view, and its sidebar and search links. (#28257)
-
Buttons, menu items, tabs and tooltips in Studio and Factory now use sentence case, so labels read the same everywhere ("Create dataset", "Edit working memory", "View in traces"). (#28131)
Also in: @mastra/playground-ui@66.0.0
-
Slack thread replies now link the pull requests, issues, commits and Linear tickets they mention instead of leaving bare IDs like
#28467orFACT-526. (#28475) -
Only a shared session's owner can change its model or thinking level now. (#28061)
-
Fixed duplicate "finished" notices from Factory sessions. (#28304)
-
Fixed Settings → Models showing a provider as Signed in after its sign-in stopped working. (#28401)
-
Factory triage now labels GitHub issues with the severity from its handoff (
severity:critical,severity:high,severity:mediumorseverity:low), alongside the existing effort and impact labels. (#28487) -
Fixed Git identity setup before session commands run so agents can commit in primary and secondary repositories. (#28292)
@mastra/fastembed@1.3.5
Patch Changes
-
Fixed FastEmbed silently returning empty embeddings for invalid setups. (#28454)
-
Use attention-mask-aware mean pooling for MiniLM and multilingual E5 embeddings while preserving BGE CLS pooling. (#28091)
-
Report missing model outputs and reject invalid numeric values from custom FastEmbed models instead of returning invalid embeddings. (#28613)
-
Fixed sparse model initialization when the cache directory has missing parent directories (#28237). (#28277)
-
Fixed empty dense and sparse embeddings when custom tokenizer metadata omits model_max_length or sets it to null (#28236). (#28279)
@mastra/inngest@1.10.8
Patch Changes
-
Fixed
InngestAgent.resume()to reject invalidmodelSettings.timeoutvalues with aTypeErrorbefore dispatching the resume, leaving suspended runs available for a retry. (#28030) -
Fixed
POST /agents/:agentId/runs/:runId/abortanswering{ aborted: false }for in-flightcreateInngestAgentruns. (#28498) -
Restore text streamed before tool approval in Inngest agents' resumed output. (#27582)
-
Brought Inngest durable agents (
createInngestAgent) in line with core's durable agent. (#28232) -
Fixed a second
InngestAgent.resume()failing with "the nested iteration snapshot does not contain suspended tool calls" when a run suspended again on a new tool call. (#27459) -
Fixed
InngestAgent.resume()ignoringhookspassed at resume time. (#27459) -
Fixed resumed Inngest agent streams staying open when the resumed run fails. (#28157)
-
Fixed resumed Inngest agent output so it includes tool calls made before suspension. (#28080)
-
Fixed Inngest agent streams so clients receive agent and message IDs before response chunks. (#27943)
-
Explicitly cancelling a disconnected Inngest run or thread prevents the agent from starting another reply. (#28162)
@mastra/koa@1.7.24
Patch Changes
- Fixed agent streams continuing after the client disconnects on Koa. (#28207)
@mastra/langfuse@1.6.3
Patch Changes
- Fixed the Langfuse trace input being replaced by the tool-approval payload after an agent suspends for tool-call approval and resumes. (#27951)
@mastra/langsmith@1.4.0
Minor Changes
- Fixed LangSmith scores being silently dropped. Scores sent with
mastra.observability.addScore()now reach LangSmith as feedback: trace-level scores (only atraceId) land on the trace's root run, and span-level scores work from any process, after a restart, or long after the span was exported. Run ids are now derived from Mastra span ids instead of being remembered in memory, so runs exported by earlier versions keep their old ids and can still only be scored from the process that exported them. Feedback also passes the id of the project the run was sent to, which LangSmith now requires.langsmithRunIdFor(spanId)is exported for linking to a run from your own UI. (#28393)
Patch Changes
- Fixed multi-turn conversations not showing up as LangSmith Threads. (#28390)
@mastra/libsql@1.27.1
Patch Changes
-
Added
batchUpdateUnendedSpans(), soMastraStorageExportercan end spans that a different process started, such as the spans a durable agent ends after recovering a run. (#28147)Also in: @mastra/pg@1.33.0
@mastra/loggers@1.3.10
Patch Changes
- Fixed a TypeScript error (
Namespace 'pino' has no exported member 'MixinFn') when@mastra/loggersis used with pino 10.4 or newer. (#28017)
@mastra/mcp@2.6.0
Minor Changes
-
Added
registerProcessHooks: falsetoMCPClientso applications can finish graceful shutdown and calldisconnect()themselves. The default remainstrue. Fixes #27478. (#28144)const mcp = new MCPClient({ servers: { weather: { url: new URL('https://example.com/mcp') } }, registerProcessHooks: false, }); process.once('SIGTERM', async () => { await mcp.disconnect(); process.exit(0); });
-
Added optional type generation for direct MCP tool calls. Generate concrete input/output interfaces from your existing clients without changing dynamic discovery or execution. (#25569)
Before:
export const mcp = new MCPClient({ servers });
After:
import { MCPClient } from '@mastra/mcp'; import type { MCPServers } from './mcp-types.generated'; export const mcp = new MCPClient<MCPServers>({ servers, typegen: { outFile: 'mcp-types.generated.ts' }, });
Run
npx @mastra/mcp generate ./client.tswith the required server credentials. The generated type-only import can be absent on the first run. File paths resolve from the command working directory. Regenerate when server schemas change.Discovered tools remain optional. Results retain protocol-envelope and validation-error alternatives; absent output schemas use
unknown. Narrow results before accessing structured fields. -
Added a
legacyoption toMCPServerthat serves MCP clients that still open withinitialize(2025-era clients such as VS Code and Cursor) over HTTP. (#28019)const server = new MCPServer({ name: 'My server', version: '1.0.0', tools, legacy: 'stateless', });
Each request from these clients is answered without a session.
GETandDELETEsession requests get405, and features that need MCP 2026-07-28 (suspend/resume,subscriptions/listen, events) aren't available to them. The default stays'reject', which answers these clients with an unsupported-protocol-version error.
Patch Changes
- Fixed
MCPServerreturning an "Invalid tools/call result" error when a tool'sexecutereturns no value. (#28438)
@mastra/memory@1.39.1
Patch Changes
-
Fixed Observational Memory injecting the continuation hint on threads that have no observations yet when retrieval is enabled. (#26826)
-
Fixed observational memory dropping messages when the Observer model returns an empty response. (#27294)
-
Fixed Observational Memory keeping a run's original user message in the prompt after it had been observed. (#28364)
-
Fixed observational memory dropping messages when the Observer model replies with text but no observations, such as a refusal ("I can't help with that"). (#28456)
-
Fixed a long agent run ending with a context-window error after observational memory had already recovered from one. (#28358)
-
Fixed per-request observationalMemory: false and { enabled: false } overrides so they disable observational memory for that request while preserving message history and subsequent enabled runs. (#28143)
-
Fixed
@mastra/memoryfailing to load in Node ESM withCannot find module 'probe-image-size/sync'. (#28139) -
Fixed working-memory data leaking into recalled history after raw message writes and partial message edits. (#28149)
-
Fixed Observational Memory calls continuing after an agent run is cancelled. (#28158)
-
Fixed Observational Memory crashing when stored conversation history contains a failed tool call with a structured error instead of a text message. (#28440)
@mastra/nestjs@0.2.39
Patch Changes
- Fixed the NestJS adapter skipping per-route authorization. (#28198)
@mastra/observability@1.22.0
Minor Changes
-
Added span-aware input, output, and error previews shared by the storage and Platform exporters. Previews use processed payloads and preserve intentionally empty strings. Exporters use core's span-aware formatter when available and otherwise preserve spans unchanged, leaving preview generation to storage. (#28442)
Existing exporter configuration enables these previews automatically:
import { MastraStorageExporter } from '@mastra/observability'; const exporter = new MastraStorageExporter();
-
Model step spans now show the
modelandproviderthe step actually called, also when an input processor switches the model or a fallback model takes over. Steps that call no model, such as a reply served from the response cache, leave both empty. (#28485)
Patch Changes
-
Update bundled model pricing with the latest prices from models.dev (
c253e13) -
Kept Vercel AI Gateway routing details (
providerMetadata.gateway.routing) on model step spans. (#28558) -
Spans keep the native
resumedFromSpanId,outcome,stopReasonandstopReasonContextfields when they are exported, snapshotted and rebuilt, so values set by a producer survive durable and multi-worker runs. (#28389) -
Fixed spans staying
RUNNINGin storage when a different process ended them under thebatch-with-updatesorrealtimetracing strategy. (#28147)
@mastra/pg@1.33.0
Minor Changes
- Added
aggregateSpans()to the PostgreSQL observability store, soPOST /observability/spans/aggregateworks with PostgreSQL. It groups the same spansquerySpans()returns and attributes token and cost usage to the span that recorded it. The store now reports thespan-aggregatefeature. (#27841)
Patch Changes
-
Fixed process crashes when a connection drops while checked out from a pool owned by PostgresStore or PgVector. (#28291)
-
Added support for recovering evented agent runs when a worker process stops. (#28054)
-
Fixed
PostgresStoreVNextfailing to initialize with "permission denied for database" when the database role can create tables in the target schema but cannot create schemas. (#28391)
@mastra/platform-workspace@1.10.0
Minor Changes
-
Added a full process manager to
PlatformSandbox. Background processes now stream their output and can be stopped: (#27919)spawn()streams stdout and stderr while the process runs, instead of only when it exits.kill()stops a process.list()shows what is running in the sandbox, plus exited processes whose output hasn't been read.get(pid)attaches to a process this manager didn't start, for example after your app restarts.
const handle = await sandbox.processes.spawn('pnpm dev', { onStdout: data => console.log(data), }); const processes = await sandbox.processes.list(); await handle.kill();
Processes have no time limit unless you set
timeout. A long-running process's output stream reconnects periodically, and the process keeps running through it. Output written during a reconnect is lost, and a process that exits while its stream reconnects reports exit code1fromwait()instead of its real exit code. -
Added an opt-in
dockersandbox setting. When it is on, E2B sandboxes get Docker Engine and Compose, and the daemon starts the first time something uses Docker. Sessions can then rundocker compose upfor local services such as Redis. (#27888)import { Template } from '@mastra/platform-workspace'; const template = Template().memoryMB(2048).docker();
In a factory, turn on the Docker switch in the sandbox settings, or pass
docker: truetocreateRepoTemplate.Docker is part of the template identity, so templates that leave it off keep their current IDs. We recommend at least 2 GB of memory for Docker.
@mastra/playground-ui@66.0.0
Minor Changes
-
Added compact options for small metrics cards in a grid: (#27980)
MetricsLineChart:lineStyle="thin"(1.5px lines, a fainter fill that fades out at both ends) anddots="hover"(a dot only on the hovered point).MetricsShareList:headerPlacement="below-strip"puts the column headers right above the rows.ChartCard:variant="compact"(title and total on one line, one card height with the chart filling it) andtitleMenuto switch views from the title. Also available asMetricsCard.TitleMenu.
<ChartCard variant="compact" title="Spend by model" titleMenu={{ value: view, onValueChange: setView, options }} total="$27.40" toolbar={<MetricsLineChartLegend series={series} />} > <MetricsLineChart data={data} series={series} height="fill" showLegend={false} lineStyle="thin" dots="hover" /> </ChartCard>
-
Added a 28px display-lg text role and an over-allowance Meter variant with a label slot and a paid-from-credits caption above the bar. Fixed open dialogs crashing when resized across the mobile breakpoint. (#28053)
Before, billing used the 22px display role and a plain meter:
<Txt variant="display">$250</Txt> <Meter value={112} max={100} aria-label="vCPU" />
Use the larger role and pass the amount charged in dollars:
<Txt variant="display-lg">$250</Txt> <Meter variant="over-allowance" value={112} max={100} paidFromCredits={4.37} label="vCPU" aria-label="vCPU" />
-
Improved span details in the trace viewer so they are easier to read: (#28559)
- Model spans show a short summary: provider and model, finish reason, time to first token, output speed, and token counts.
- Tools available to a span get their own Tools section. Workflow tools (
workflow-<key>) and sub-agent tools (agent-<key>) link to their workflow or agent page. - Skills catalogs in system prompts appear as a list of skills instead of raw XML.
- Stored messages show up as chat bubbles in every span. Reasoning and tool calls no longer appear as raw JSON.
- Processor and chunk spans with an empty
{}output no longer show an Output section. - The span header shows the run id, and span and trace durations use the same format.
-
Added
MetricsTable,SeriesMarkandSparklinefor the numbers behind a chart, and a title link onChartCard. (#28481)MetricsTablelists one row per series or group, with lines between rows that fade at the ends. Columns set their own cell, width, alignment and sort value. Sort can be controlled (for example kept in the URL), and row hover and click let the table act as the chart's legend.SeriesMarkties a row to its chart series: a small color square, or an icon such as a provider logo drawn in the series color on a tinted square.Sparklinedraws a tiny trend line for a row.ChartCardtakeshref(andLinkComponent) to make its title a link to a fuller view of the chart, marked by an expand icon.DropdownMenu.RadioOptionstakescloseOnSelectto close the menu when an option is picked.
import { MetricsTable } from '@mastra/playground-ui/components/MetricsTable'; import { SeriesMark } from '@mastra/playground-ui/components/SeriesMark'; <MetricsTable rows={models} getRowKey={m => m.id} columns={[ { id: 'name', header: 'Model', width: 'minmax(0,1fr)', cell: m => ( <> <SeriesMark color={m.color} /> {m.name} </> ), }, { id: 'spend', header: 'Spend', align: 'end', cell: m => m.spend, sortValue: m => m.rawSpend }, ]} />;
-
Added public components and hooks for end-user connection flows. (#26928)
Connect hooks
The
@mastra/playground-ui/domains/connectentry point now exports hooks for loading the connect surface, listing providers and connections, creating and disconnecting connections, polling status, and driving an authorization flow withusePendingConnect().const { connect, cancel, pending, settled } = usePendingConnect() <Button onClick={() => connect(provider)}>Connect</Button> {pending ? <Button onClick={cancel}>Cancel</Button> : null} {settled?.status === 'failed' ? <p>{settled.message}</p> : null}
usePendingConnect()accepts the provider and optional form values, uses provider-direct headless authorization when supported, falls back to hosted authorization when required, and exposes pending and settled state for custom UIs.Connect primitives
Added
ProviderLogoplus headless authorization helpers for detecting supported flows, deriving form fields, splitting credentials from flow parameters, and starting authorization.Connect prompt card
Added the exported
ConnectPromptToolcard for structuredrequest_connectionoutput. It renders inset provider rows with consistent logos, clear connected states, Connect actions, and read-only historical states. -
Added composable
ComposerHeader,ComposerHeaderRow,ComposerHeaderContent, andComposerHeaderActionscomponents for connection status, ownership controls, and other context above a chat input. The header handles the joined surface and collapses when its children render nothing. Setopento animate visibility with reduced-motion support; rows support destructive and success tones. (#27960)<Composer> <ComposerHeader> <ComposerHeaderRow> <ComposerHeaderContent>You're viewing Sam's session.</ComposerHeaderContent> <ComposerHeaderActions> <Button type="button" onClick={takeOwnership}> Take ownership </Button> </ComposerHeaderActions> </ComposerHeaderRow> </ComposerHeader> <ComposerBox> <ComposerInput aria-label="Message" /> </ComposerBox> </Composer>
-
Icon-only buttons are now circles everywhere. Before, a
Buttonholding only an icon with a text size (sm,md,lg) rendered as a padded pill, while others used the roundicon-*sizes. All built-in icon-only buttons (panel close, previous/next, copy, code section and filter actions) now useicon-sm,icon-mdoricon-lg. (#28110)CopyButtonnow takes only icon sizes and defaults toicon-sm:// Before <CopyButton content={id} size="sm" /> // After <CopyButton content={id} /> <CopyButton content={id} size="icon-md" />
For your own icon-only buttons, pick the icon size of the same height:
// Before: renders as a pill <Button size="sm" aria-label="Close"><XIcon /></Button> // After: a circle of the same height <Button size="icon-sm" aria-label="Close"><XIcon /></Button>
-
Added shared building blocks so any React Router app can show the Traces, Spans and Threads pages under one header that stays mounted when switching views. (#28270)
New exports
ObservabilityPageLayoutfrom@mastra/playground-ui/domains/observability: breadcrumbs plus the Traces / Spans / Threads switch. Wrap your page routes with it and pass your router's outlet as children.SpansExplorerBodyandThreadsExplorerBody: the full spans and threads page bodies (filters, list, panel). They take the selection and callbacks as props, so they work with any router.TracesExplorer.Body: the traces list without its own page header, for use insideObservabilityPageLayout.TracesExplorer.Layoutis unchanged.- Helpers:
ObservabilityCapabilityGate,ObservabilityListBody,useObservabilityViews,useObservabilityListFilters,observabilityViewCrumbLabeland URL selection helpers (readSpanSelection,withSpanSelection,readThreadSelection,withThreadSelection,spanTraceSearch).
function ObservabilityRoute() { const navigate = useNavigate(); return ( <ObservabilityPageLayout current={viewFromPathname(useLocation().pathname)} features={{ spanQuery: true, threadQuery: true }} onViewChange={view => navigate('/' + view)} breadcrumbs={state => <MyBreadcrumbs label={observabilityViewCrumbLabel(state)} />} > <Outlet /> </ObservabilityPageLayout> ); }
-
Added a Breakdown card to the Metrics page. One sortable table, with no share bars or colours, ranks agents, workflows, tools, models, threads and environments, plus projects on pages that cover several projects. (#28272)
- Count column: traces for agents, workflows, threads, environments and projects (an agent counts each trace it ran in once, nested runs included, so a subagent that never starts a trace still shows up); spans for tools and models, since one trace can call a tool or model many times. Model spans are counted from model usage events, so calls that report no usage aren't counted. A tooltip on the header explains whichever one the tab counts.
- Errors, P95 latency, Tokens and Cost where the tab has them. Workflows and tools have no token usage; models have no errors or latency.
- % Change against the previous range of the same length, as the last column, right after the count. It follows the sorted column, so sorting by Cost shows how each row's cost moved, and sorting by % Change ranks the rows that moved most. Its header tooltip names the figure it compares and the dates of both ranges.
- Project, on pages that cover several projects (
MetricsProviderscope.projectLabelset), right after the name on every tab but Projects. It showsprojectLabel(projectId), and a dash for rows without a project. Resource on the Threads tab.
Clicking a row opens its traces. The card replaces Trace volume and Usage when observability storage supports both trace and span aggregation (ClickHouse, Postgres and DuckDB today). Other storage keeps the page as it was.
Also added:
MetricsShareList: sortable column headers (onSortChange,sort,valueSortKey, andsortKeyper column), header tooltips (descriptionper column,valueDescription), left-aligned text columns (align: 'left'), which sit right after the label, before the number columns,emphasiscolumns in the main value's colour,showShare={false}to hide the Share column, andshowStrip={false}for a plain table without the strip and row swatches. When shown, the strip and row colours follow share, whatever the sort.- A
spandrilldown scope ({ spanTypes, entityName, status? }) onbuildTracesDrilldownUrl, which opens traces containing a matching span. bodyHeight="fit"onChartCard, for lists that grow past one chart's height.useMetricsUsageTotals: tokens and cost, or counted model calls, per group over any window. Cards that ask for the same grouping share one request.
-
The Metrics page Latency card now charts P99 alongside P50 and P95 for agent runs, workflow runs and tool calls, so slow outliers show up without opening traces. It also loads only the tab you have open, instead of all three at once. (#28272)
useMetricsLatency(entity)now takes the entity type to load, and its buckets usep50,p95andp99keys. -
Added a Resources and threads card to the Metrics page. It charts distinct resources and threads with traces over time, with each id's total for the whole range in the legend, and adds users and sessions when your traces set
userIdorsessionId. Ids your traces don't set are left out rather than drawn as flat lines. Click a bucket to open its traces. (#28272)The card appears when your observability storage supports both trace and span aggregation (ClickHouse, Postgres and DuckDB today); other storage keeps the page as it was. It shows a message instead of data when a page filter has no trace equivalent.
DistinctIdsCardis exported from@mastra/playground-ui/domains/metrics/componentsand takes its drilldown as a callback prop, so other apps can place it on their own Metrics pages inside aMetricsProvider. -
Added a Threads view to the traces explorer. It lists conversation threads with the same filters, time range, sorting and infinite scroll as the spans view, and opens the full thread in a drawer. The Threads tab is off by default. Hosts turn it on with
features.threadQuery, and it only shows when the observability store can return thread rows. (#28241)<TracesExplorer features={{ spanQuery: true, threadQuery: true }}>…</TracesExplorer>
TraceThreadPanelalso accepts acloseLabelprop to rename its close button. -
CodeDiffcan now carry a file header. Passheaderwith the file'spathand it shows above the diff, with an optionaliconbefore the path (the kind of change), your ownmeta(line counts) on the right, and a chevron that folds the diff away.previousPathadds a "from" line for renamed or moved files. With a header and nopatch, the card shows the header alone, for files with no diff to show such as binaries or oversized changes. (#28274)Added
CodeDiffList, a scroll container for manyCodeDiffs. It stacks them edge to edge with a divider between files, the way a pull request does, and only renders the diff lines in view, so a change set with hundreds of files stays fast. Each file header stays pinned while you scroll through its diff.import { CodeDiff, CodeDiffList } from '@mastra/playground-ui/components/CodeDiff'; import { DiffStat } from '@mastra/playground-ui/components/DiffStat'; import { SquareArrowRight } from 'lucide-react'; <CodeDiffList className="h-[640px]"> <CodeDiff patch={agentPatch} overflow="scroll" header={{ path: 'src/agent.ts', meta: <DiffStat additions={4} deletions={1} /> }} /> <CodeDiff header={{ path: 'src/agents/helper.ts', previousPath: 'src/helper.ts', icon: <SquareArrowRight role="img" aria-label="Renamed" />, }} /> </CodeDiffList>;
CodeDiffalso takesoverflow.wrap(default, as before) breaks long lines, which suits prose.scrollkeeps each line on one row behind a horizontal scroll, which suits source code; in the split layout each side scrolls on its own.Added
DiffStat, the green+Nand red−Nline counts of a change. It takes the surrounding text style, and screen readers hear "4 additions and 1 deletion" instead of the symbols. -
Added
RotatingText, a styleless component that shows a list of messages one at a time in random order. Use it to show what a long-running task is busy with, for example in an empty state. (#28133)import { RotatingText } from '@mastra/playground-ui/components/RotatingText'; <EmptyState titleSlot="Experiment in progress" descriptionSlot={<RotatingText messages={['Calling your target…', 'Consulting the scorers…']} />} />;
-
Added
@mastra/playground-ui/oxlint, an oxlint plugin with the design system's lint rules, so apps built on Playground UI can enable the same rules as Studio. Load the plugin and spread the recommended rules into your oxlint config: (#28126)import { recommended as playgroundUiRules } from '@mastra/playground-ui/oxlint'; import { defineConfig } from 'oxlint'; export default defineConfig({ jsPlugins: ['@mastra/playground-ui/oxlint'], rules: { ...playgroundUiRules }, });
The rules flag icon-only buttons without an
icon-*size, Tailwind text sizes instead of text roles, text colour classes andfont-monoon<Txt>, and imports from broad package barrels. -
Data layer for Metrics cards built on trace and span aggregates, shared by Studio and pages that span several projects. (#27908)
useMetricsLayout()says which Metrics page to render:unifiedwhen the server answers bothaggregateTraces()andaggregateSpans(), otherwiselegacy, the page as it was. Studio can be upgraded without its storage, so the page falls back instead of showing empty cards.MetricsProvidertakes an optionalscope. PassprojectLabelon a page that spans several projects; cards then add a Project dimension, and drilldowns receive the row'sprojectId.
<MetricsProvider {...props} scope={{ projectLabel: id => projectNames[id] ?? id }}> <MetricsPage /> </MetricsProvider>
- Every card on the page now shares one time window, so cards asking the same question send one request.
AggregateLimiterProvider, exported from@mastra/playground-ui/domains/metrics/components, caps trace and span aggregates together at 3 in flight, in page order.MetricsProvideralready renders one; render it higher up to share the cap across several providers. A request that has started always finishes, so remounting a card (for example under StrictMode) no longer sends it twice.
-
Added quieter Notice and toast surfaces, with more control over Notice actions. (#28357)
- Notice:
actionPlacement="end"puts the action beside the message, andonDismissadds a close button.Noticealso accepts nativedivprops and a ref. - Toast: surfaces match Notice, actions sit below the message, and long content scrolls inside the toast.
<Toaster variant="neutral">keeps every tone on a gray surface with its semantic icon. - Promise toasts: the loader turns into a check or an ×, and the dismiss timer starts only once the promise settles.
<Notice variant="info" actionPlacement="end" action={<Button>View setup</Button>} onDismiss={dismiss}> Push to a linked branch to create your first deploy. </Notice>
- Notice:
-
Added explicit source units to
formatByteswith opt-in automatic scaling. Existing byte-only calls keep their output. (#28458)import { formatBytes } from '@mastra/playground-ui/utils/number'; formatBytes(1536); formatBytes(0.5, { unit: 'GB' }); formatBytes(0.5, { unit: 'GB', autoScale: true });
These return
1.5 KB,0.5 GB, and512 MB, respectively. A supplied unit stays fixed whenautoScaleis absent or false. Conversions retain the helper's binary 1024-based convention, not decimal SI units. -
Added a Time to first chunk column to the Traces page. Pick it from the Columns menu to see how long each run took to stream its first chunk back. Runs that never streamed show a dash. Click the column header to sort traces by it. The column is only offered when the observability store records this value, and the header is only sortable when the store can order by it. When the store doesn't support it, or the column is hidden, the list falls back to newest first instead of showing an always-empty column or an unusable sort. (#28566)
Breaking:
TracesExplorernow takes the sort as a single{ field, direction }value so it can sort by more than the start time. ReplacesortDirection/onSortDirectionChangewithsort/onSortChange:// Before <TracesExplorer sortDirection={direction} onSortDirectionChange={setDirection} />; // After import { DEFAULT_TRACES_SORT, type TracesSort, } from '@mastra/playground-ui/domains/traces/components/traces-explorer'; const [sort, setSort] = useState<TracesSort>(DEFAULT_TRACES_SORT); <TracesExplorer sort={sort} onSortChange={setSort} />;
fieldis'startedAt'or'timeToFirstChunkMs'. -
Added a
sizeprop toDrawerandDrawerContentfor wider left and right drawers.mdkeeps the current widths,lgis 42rem andxlis 56rem, and floating drawers size their viewport to match. Fixed a sideways trackpad bounce inside drawers in Chrome. Fixed tabs inside a drawer not switching on click: pressing a tab started the drawer's swipe instead. (#28275)<Drawer side="right" variant="floating" size="lg"> <DrawerContent> <DrawerHeader> <DrawerTitle>Connect</DrawerTitle> </DrawerHeader> <DrawerBody>…</DrawerBody> </DrawerContent> </Drawer>
-
Reworked the trace details panel so it is easier to scan and sized to the trace you open. (#28117)
Header
- The top row holds trace navigation, the trace ID (first 6 characters, click to copy) and the actions, in this order: Score trace, Add to dataset, Open trace page, Download trace JSON, then Close.
- A second row shows the entity, a status badge and timing, token and cost metadata. While the trace loads, this row shows a skeleton.
Sizing
- Agent traces open the drawer at 80% width, or full width with a span open. Other traces open at 50%, or 80% with a span open, because they have no Messages column.
- The side column and span column now keep a fixed pixel width when the drawer changes size. The widths you set by dragging are remembered per entity type. The columns open at those widths while the trace is still loading.
Removed the auto refresh toggle
The traces list now always polls for new traces, so the "Auto refresh" checkbox is gone. Remove
TracesExplorer.AutoRefreshfrom your layout.useTracesListSourceno longer returnssetAutoRefetch, and itsinitialAutoRefetchoption is nowautoRefetch.// Before <TracesExplorer.AutoRefresh />; useTracesListSource({ initialAutoRefetch: false }); // After useTracesListSource({ autoRefetch: false });
Other additions
- Added
TraceScoresList, a compact list of a trace's scores. - Added an
entityTypeprop onTraceSpanPanelandTraceDataPanelViewthat sizes the columns before the trace loads. - Added an
ellipsisprop onDataPanel.CopyIdto truncate without the trailing "…".
-
Added composable building blocks for the spans page so host apps can build their own spans filter bar, detail panel and view switch. (#28164)
Compose the spans filter bar
useSpansFilterBarFieldsanduseSpansFilterBar(from@mastra/playground-ui/domains/spans/hooks) expose the fields and value thatSpansFilterBaruses, so you can add your own chips next to the span ones. They mirroruseTracesFilterBarFieldsanduseTracesFilterBar, but take the span filter state as arguments:const spanFields = useSpansFilterBarFields({ timeRange }); const { filterBarValue, onFilterBarChange, onFilterByField } = useSpansFilterBar({ tokens, groups, onFiltersChange }); <FilterBar fields={[projectField, ...spanFields]} value={{ ...filterBarValue, nodes: [...filterBarValue.nodes, ...projectItems] }} onValueChange={next => onFilterBarChange({ ...next, nodes: next.nodes.filter(node => !isProjectNode(node)) })} />;
The time range chip is always part of
filterBarValueand is never passed toonFiltersChange.onFilterByField(fieldId, value)replaces any filter on that field withis value, for example from a list cell. MemoizetimeRangeso the fields list stays stable between renders.New
SpansFilterBarpropsminDatelimits how far back the time range picker goes.describeSuggestionsErrorlets you replace the message shown when value suggestions fail to load.
New components
SpanDetailPanel(and theSpanSelectiontype) loads a span and wires previous/next navigation, without any drawer or side panel chrome.TracesSpansSwitchandTracesSpansSwitchSkeletonrender the Traces/Spans tabs. PassonViewChangeto decide what switching does instead of relying on hardcoded/tracesand/spansroutes.
Patch Changes
-
Added a Messages column to the Threads list showing how many messages each thread has. (#28610)
-
Fixed searchable submenu padding and kept search headers outside scrolling options. (#28597)
-
Fixed chart y-axis labels showing extra zeros, such as $0.0 and $5.0. (#28243)
-
Improved image attachments in chat messages: images now show unobscured, with the file name and type in a row below them instead of over the lower half of the image. (#28642)
-
Fixed model pickers to show newer releases first in Studio and Factory, with alphabetical fallback for undated models. (#27661)
-
Improved menu typography and spacing with softer labels, lighter icons, and coordinated hover and keyboard highlights. (#28121)
-
Metrics cards in the same row now end at the same height. (#26888)
-
Fixed the keyboard focus ring on sidebar links being cut off at the edges, most visibly on the first link in a sidebar that uses
Sidebar.NavStack. (#28107) -
Thread panel now loads 3 turns at a time instead of 10, both when it opens and when you scroll up to load older turns. (#28305)
-
Fixed Metrics charts for ranges longer than 14 days dropping the first day and mislabeling days when the browser isn't on UTC. (#28062)
-
Fixed context menus so a second right-click opens the browser menu, including native link actions. (#28114)
-
Added an optional
valuetoThinkingLevelUnavailable, so a control that is locked rather than unsupported still shows the level in effect, and screen readers hear it (`Thinking: Medium. (#28061) -
Sidebar sub-menus (
Sidebar.NavStack) now remove the menus you aren't on from the page once their fade-out finishes, instead of keeping them rendered and invisible. (#28112) -
The Metrics date picker no longer lets you pick a custom range that starts before the oldest trace your storage still keeps, so cards don't show an empty start that looks like missing data. (#28272)
-
Fixed
MetricsTablerow content sitting 1px low: the separator line is drawn inside each row's bottom edge, so rows now get one more pixel of bottom padding and their content is centered between the lines above and below it. (#28616) -
JSON in code editors, trace span payloads (Input, Output, Metadata, Attributes), dataset items, data detail panels and tripwire metadata can now be collapsed and expanded with the square toggle next to each object or array. (#28102)
-
Added
parseSkillBody(name, text)to read skill text when the skill name is passed separately, as with skill signals. (#27150) -
Fixed type declarations for
@mastra/playground-ui/lib/form/types,@mastra/playground-ui/ee/topics/typesand other type-only entry points, which were previously published empty. (#27815) -
Fixed context menus on macOS so a second Control-click opens the browser menu, the same as a second right-click. (#28136)
-
Fixed Studio reloading the whole page after a shared component edit during development. (#28104)
-
Added a Columns menu to the Spans page. (#28562)
-
Fixed items in the collapsed sidebar jumping while it collapses. (#28109)
-
Agent runs started by a signal now show what started them in traces, instead of a raw JSON dump of the signal. (#28038)
-
Added live updates to the Spans and Threads lists. (#28591)
-
Re-exported
useSpanQueryAvailablefrom@mastra/playground-ui/domains/capabilities, and added a spans filter bar (@mastra/playground-ui/domains/spans) that offers only the fields the span query accepts. (#27989) -
Fixed toast styles that referenced an undefined corner radius token. (#28557)
-
Renamed the Model filter to Span Model on the Traces, Spans and Threads pages, so it is clear the filter matches the model recorded on spans. (#28682)
-
ProviderLogonow draws the Typesafe mark in its brand magenta for thetypesafeprovider (Jev Router) instead of the generic models.dev fallback. (#28684) -
Fixed chart y-axes topping out far above the data: a $4.40 peak now gets a $5 axis instead of $8. (#27980)
-
AppShellandMainCardtake anedgeToEdgeprop. (#28300) -
Fixed the sort icon on right-aligned sortable columns (such as TTFC in the traces list) appearing before the column label. (#28681)
@mastra/react@1.13.0
Minor Changes
-
Added
useQuerySpansanduseSpanQueryAvailablehooks for listing individual spans from observability stores that support span queries.useQuerySpansloads spans with cursor-based infinite scroll: attachsetEndOfListElementto the last row and the next page loads when it scrolls into view. You can also callfetchNextPageyourself, andhasNextPagetells you whether more spans remain. (#27989)import { useSpanQueryAvailable } from '@mastra/react/hooks/capabilities'; import { useQuerySpans } from '@mastra/react/hooks/traces'; const { enabled } = useSpanQueryAvailable(); const { spans, hasNextPage, isFetchingNextPage, setEndOfListElement } = useQuerySpans({ query: { timeRange: { from, to }, orderBy: [{ field: 'startedAt', direction: 'desc' }] }, enabled, });
-
Added
useTraceAggregateanduseSpanAggregate, hooks that runclient.aggregateTraces()andclient.aggregateSpans()and return grouped counts, error rates, latency percentiles, tokens and cost. They only refetch when the request changes or you callrefetch(). CheckuseTraceAggregateAvailable()oruseSpanAggregateAvailable()before enabling them. (#27908)import { useSpanAggregate } from '@mastra/react/hooks/traces'; const { data } = useSpanAggregate({ request: { timeRange: { from, to }, where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'tool_call' } }, groupBy: ['entityName'], measures: ['count', 'errorRate', 'duration.p95'], }, });
-
Added
useQueryThreadsanduseThreadQueryAvailablehooks to list thread rows from the thread query API, with filters, sorting and infinite scroll. (#28241)import { useThreadQueryAvailable } from '@mastra/react/hooks/capabilities'; import { useQueryThreads } from '@mastra/react/hooks/traces'; const { enabled } = useThreadQueryAvailable(); const { threads, setEndOfListElement } = useQueryThreads({ query: { timeRange: { traces: { from, to } }, orderBy: [{ field: 'startedAt', direction: 'desc' }], }, enabled, });
-
Added
useSpanAggregateAvailable(), which reports whether the server supportsaggregateSpans(). (#27827)const { isLoading, enabled } = useSpanAggregateAvailable(); if (!isLoading && enabled) { // render span aggregate charts }
Patch Changes
-
useDatasetMutations().triggerExperimentacceptsagentModelto run an agent experiment against a different model. (#28165) -
Fixed useChat to stop running on matching thread-run-status outcomes while preserving suspended approvals and ignoring outcomes from other runs. (#28621)
-
Pending steers and queued follow-ups now appear immediately in React chat clients, settle into delivered messages without duplication, and disappear when cancelled. (#28204)
-
Make
useChatStop cancel the active durable run, including runs without a memory thread, instead of only closing the response stream. (#28162) -
Added an optional
scopeargument touseTraceColumnPreferencesStorageKeyso traces and spans can save their column choices under separate keys. (#28562)
@mastra/redis@1.4.12
Patch Changes
RedisServerCache.listPushIndexedaccepts an optional TTL as its fourth argument. (#27352)
@mastra/redis-streams@0.7.0
Minor Changes
-
Added
retainTerminalEventstotrimTopicto preserve compact run outcomes and execution authority metadata while removing saved output. Upgrade alongside@mastra/corefor opted-in thread outcome recovery. (#28621)await pubsub.trimTopic(topic, { runId, retainTerminalEvents: true });
@mastra/s3@0.6.5
Patch Changes
- Added Neon Object Storage detection to
S3Filesystem. (#28032)
@mastra/server@1.80.0
Minor Changes
-
Added an
agentModelfield toPOST /datasets/:datasetId/experiments, for example{ "agentModel": { "provider": "anthropic", "modelId": "claude-haiku-5-5" } }, to run an agent experiment against a different model. The request is rejected whentargetTypeis not"agent"or whenstartisfalse. (#28165) -
Added
POST /observability/spans/aggregate, which groups and measures individual spans (counts, durations, error rates, tokens, cost) over a time window.GET /observability/capabilitiesnow reportsspanAggregate; the route returns 501 when the configured observability store does not support span aggregation. (#27827)POST /observability/traces/aggregateandPOST /observability/spans/aggregatenow return a structured 503 (TRACE_QUERY_RESOURCE_LIMIT) when a query exceeds a database resource limit, matching/spans/query. Previously the trace aggregate route returned a 500.POST /api/observability/spans/aggregate:{ "timeRange": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-08T00:00:00Z" }, "where": { "op": "eq", "left": { "path": "spanType" }, "right": { "literal": "agent_run" } }, "groupBy": ["status"], "interval": "1d", "measures": ["count"] }
Patch Changes
-
Return HTTP 409 Conflict from
POST /agents/:agentId/recoverwhen the run is no longer active. (#28611) -
Detach disconnected HTTP observers from durable and evented agent runs instead of aborting execution. (#28162)
-
Fixed Studio overrides for file-based agents to store and export only fields allowed by the agent's
editorownership settings. (#28159) -
Fixed HTTP agent observation to emit public stream frames directly instead of internal PubSub envelopes, restoring text, tool results, and finish metadata when reconnecting. (#28618)
-
Dataset item schema validation errors now tell you which fields failed, on every server adapter (Hono, Express, Fastify, Koa, Elysia, NestJS). (#28211)
-
Fixed agent-controller stream errors dropping the provider's status code, response body, request id and requested model when flattened for the wire. (#27811)
-
Agent-controller stream errors now carry every provider code and the provider's
reasonsentence, built by the same core function that saves the error to thread history, so a live error and a reloaded one are the same object. (#28496)
@mastra/server-adapters-test-suite@0.2.0
Minor Changes
-
Added
createStructuredWakeTestSuiteto check that idle-thread subscriptions receive structured results and validation errors before the terminal event on plain, durable, and evented agents. (#28617)Pass your adapter's scripted model fixture as
setupModeland its real HTTP server factory asstartServer:import { createStructuredWakeTestSuite } from '@mastra/server-adapters-test-suite'; createStructuredWakeTestSuite({ setupModel, startServer });
Patch Changes
-
Add a reusable real-HTTP disconnect suite covering durable and evented stream starts, resumes, tool approvals, observer replay, and explicit cancellation, with ordinary agents as the cancellation control. (#28162)
-
Removed the
supportsRBACoption from the adapter test suite config. (#28205) -
Server adapters tested with the shared route suite now pass for the MCP server event routes (
/mcp/:serverId/events/:eventName/poll,/stream,/emit) andPOST /observability/spans/aggregate. (#28116) -
Skipped the run-scoped abort route (
POST /agents/:agentId/runs/:runId/abort) in the generic adapter route suite, since it returns 501 for the suite's non-durable agent by design. (#28301)
@mastra/slack@1.8.0
Minor Changes
-
Added
textDisplayto the Slack provider and adapter config. SettextDisplay: 'hidden'to keep the agent's reply text out of Slack threads, for example when the agent replies through a tool. Tool display, approval prompts, errors and typing status still show. (#28067)new SlackProvider({ textDisplay: 'hidden' });
Patch Changes
- Slack apps created by
SlackProvidernow request thefiles:writebot scope, so agents can post file attachments to a thread. (#27351)
@mastra/temporal@0.4.18
Patch Changes
-
Fixed
run.start()on Temporal workflows returningsteps: {}. (#28397) -
Fixed Temporal workflow outputs being wrapped in an extra result object. (#28153)
@mastra/valkey@0.2.8
Patch Changes
ValkeyServerCache.listPushIndexedaccepts an optional TTL as its fourth argument. (#27352)
@mastra/voice-speechify@0.15.0
Minor Changes
-
Default to Speechify's Simba 3.5 and move to the
@speechify/apiSDK. (#28513)simba-3.5is Speechify's recommended model: 48 languages on one id, and every catalog voice, cloned voices included, speaks all of them. Passlanguageto choose one; without it the voice's own locale decides.simba-3.2andsimba-3.0stay selectable.simba-englishandsimba-multilingualare retired for new workspaces and are served bysimba-3.2andsimba-3.5from 2026-11-21.import { SpeechifyVoice } from '@mastra/voice-speechify'; const voice = new SpeechifyVoice(); // simba-3.5 with the harper_32 voice await voice.speak('Olá, mundo', { language: 'pt-BR' });
- The deprecated
@speechify/api-sdkis replaced by@speechify/api. Thespeak()options arespeaker,model,language,audioFormat(mp3,ogg,aacorpcm),outputFormatandoptions;optionskeys now follow the API's snake_case, such asloudness_normalization. getSpeakers()reads Speechify's catalog live and reports each voice's name, locale, gender and the models that render it. The bundled voice list is gone: most of its ids no longer existed, and it was missing over nine hundred current voices.speakeraccepts any catalog id.- Requests carry
Speechify-Caller: mastraand the package version, so Speechify can warn before a model change reaches Mastra users.
- The deprecated
Other updated packages
Dependency updates only: @mastra/acp@0.4.4, @mastra/agent-browser@0.5.5, @mastra/agentcore@0.5.3, @mastra/apple-container@0.5.2, @mastra/archil@0.3.2, @mastra/arize@1.3.27, @mastra/arthur@0.4.27, @mastra/astra@1.1.3, @mastra/auth@1.1.5, @mastra/auth-auth0@1.2.6, @mastra/auth-better-auth@1.1.9, @mastra/auth-clerk@1.3.2, @mastra/auth-cloud@1.2.8, @mastra/auth-firebase@1.1.5, @mastra/auth-google@0.1.7, @mastra/auth-neon@0.3.5, @mastra/auth-okta@0.2.6, @mastra/auth-supabase@1.1.6, @mastra/auth-workos@1.6.8, @mastra/azure@0.3.3, @mastra/azure-ai-search@0.1.2, @mastra/blaxel@0.10.2, @mastra/braintrust@1.3.24, @mastra/browser-viewer@0.2.6, @mastra/chroma@1.1.5, @mastra/claude@0.3.4, @mastra/cloudflare@1.7.6, @mastra/cloudflare-sandbox@0.5.4, @mastra/codemod@1.1.8, @mastra/convex@1.7.6, @mastra/cursor@0.3.4, @mastra/datadog@1.4.19, @mastra/daytona@0.11.4, @mastra/deepeval@0.1.21, @mastra/discord@1.3.2, @mastra/docker@0.12.1, @mastra/evals@1.10.9, @mastra/files-sdk@0.3.3, @mastra/gcs@0.3.5, @mastra/google-drive@0.2.4, @mastra/isolated-vm@0.1.4, @mastra/laminar@1.3.29, @mastra/livekit@0.5.2, @mastra/longmemeval@1.1.39, @mastra/mcp-docs-server@1.3.10, @mastra/mcp-registry-registry@1.1.7, @mastra/openai@1.1.4, @mastra/opencode@0.1.39, @mastra/oracledb@0.5.5, @mastra/otel-bridge@1.5.19, @mastra/otel-exporter@1.4.10, @mastra/parallel@0.1.4, @mastra/pinecone@1.1.3, @mastra/posthog@1.4.4, @mastra/qdrant@1.1.6, @mastra/quickjs@0.1.5, @mastra/rag@2.7.1, @mastra/railway@0.10.2, @mastra/s3vectors@1.1.5, @mastra/schema-compat@1.3.17, @mastra/sentry@1.2.29, @mastra/spanner@1.10.1, @mastra/sprites@0.1.2, @mastra/stagehand@0.3.7, @mastra/teams@0.1.3, @mastra/telegram@0.2.4, @mastra/turbopuffer@1.2.3, @mastra/turso@0.1.18, @mastra/upstash@1.5.5, @mastra/vectorize@1.1.4, @mastra/vercel@1.6.2, @mastra/voice-aws-nova-sonic@0.2.6, @mastra/voice-azure@0.12.3, @mastra/voice-cloudflare@0.13.4, @mastra/voice-deepgram@0.13.3, @mastra/voice-elevenlabs@0.13.3, @mastra/voice-gladia@0.13.3, @mastra/voice-google@0.14.4, @mastra/voice-google-gemini-live@0.14.18, @mastra/voice-inworld@0.4.6, @mastra/voice-mistral@0.1.3, @mastra/voice-modelslab@0.2.3, @mastra/voice-murf@0.13.3, @mastra/voice-openai@0.13.4, @mastra/voice-openai-realtime@0.14.8, @mastra/voice-playai@0.13.3, @mastra/voice-sarvam@1.1.4, @mastra/voice-xai-realtime@0.2.17, @mastra/voyageai@0.4.3, @mastra/weaviate@0.1.4