Highlights
Reusable Sandbox Templates + Warm Repo Checkouts (E2B & Platform)
New reusable template APIs in @mastra/platform-workspace plus @mastra/e2b repo templates let sandboxes start from a pre-cloned, pre-built repository image (with background rebuilds and resource sizing), dramatically reducing cold-start time for code sessions and workspace-backed agents.
Unified workingDirectory Across All Sandbox Providers
A new workingDirectory option in MastraSandboxOptions is now honored by every sandbox provider (with a sandbox.workingDirectory getter), standardizing default command/process CWD behavior across Docker/E2B/Vercel/Railway/etc. while still allowing per-command cwd overrides.
Client-Side Tools Can Use Server-Defined toModelOutput
Client-executed tools (browser tools without execute) now support server-defined toModelOutput, so the server can transform the returned payload into model-ready content (e.g., turning { fileId, dataUrl } into an image content part) without custom input processors.
Observability Feedback Review Workflow (API + Storage + UI Plumbing)
Feedback records now support reviewStatus (needs-review/reviewed) with filtering in listFeedback, a new storage method updateFeedbackReviewStatus, and a new server endpoint PATCH /api/observability/feedback/:feedbackId/review-status exposed in @mastra/client-js.
New @mastra/evals/vitest Test Runner Integration
@mastra/evals/vitest lets you run runEvals as Vitest tests with expectEvals/expectEval, optional matchers, and a reporter that prints per-test scores—making evals easier to gate in CI.
Breaking Changes
@mastra/factory:sandboxconfig is now a callback (ctx => new E2BSandbox({ id: ctx.sessionId })) rather than an options object;workdir/maxSandboxesand the sandbox fleet/reattach model are removed.@mastra/playground-ui:Chip,ChipsGroup, andStatusBadgewere removed in favor of a singleBadgecomponent (now a<span>with updated prop typing).
Changelog
@mastra/core@1.64.0
Minor Changes
-
Added a review workflow status to observability feedback. (#22805)
- Feedback records now carry a
reviewStatus(needs-review|reviewed), defaulting toneeds-reviewand settable at creation;listFeedbackcan filter on it. - New storage method
updateFeedbackReviewStatusandPATCH /api/observability/feedback/:feedbackId/review-statusendpoint (requiresobservability:write), exposed on the client asupdateFeedbackReviewStatus.
const { feedback } = await client.listFeedback({ filters: { reviewStatus: 'needs-review' }, pagination: { page: 0, perPage: 20 }, }); await client.updateFeedbackReviewStatus({ feedbackId: feedback[0].feedbackId, reviewStatus: 'reviewed', });
Also in: @mastra/client-js@1.43.0, @mastra/server@1.64.0
- Feedback records now carry a
-
Added support for server-defined
toModelOutputon client-side tools. When a tool without anexecutefunction runs in the browser and sends its result back, the server tool definition'stoModelOutputnow transforms that result before the model sees it — matching AI SDK behavior. This lets a client tool return a compact payload (like an uploaded file id or base64 image) and have the server map it into real model content: (#22437)import { createTool } from '@mastra/core/tools'; import { z } from 'zod'; // No execute: the browser runs this tool and returns { fileId, dataUrl } const takeScreenshot = createTool({ id: 'takeScreenshot', description: 'Captures the screen', inputSchema: z.object({}), outputSchema: z.object({ fileId: z.string(), dataUrl: z.string() }), toModelOutput: output => ({ type: 'content', value: [{ type: 'image-url', url: output.dataUrl }], }), });
Previously the model only ever saw the raw JSON tool result and transforming it required a custom input processor.
-
Added a
workingDirectoryoption toMastraSandboxOptions, honored by every sandbox provider (#22697)Every sandbox now accepts one instance-level
workingDirectoryoption that sets the default directory for command execution and process spawns. A per-commandcwdalways wins over it, and when neither is provided each provider keeps its previous default (E2B home, docker/workspace, Vercel serverless/tmp, and so on). The effective value is readable through the newsandbox.workingDirectorygetter.const sandbox = new E2BSandbox({ workingDirectory: '/home/user/my-repo' }); await sandbox.executeCommand('pwd'); // /home/user/my-repo await sandbox.executeCommand('pwd', [], { cwd: '/tmp' }); // /tmp
Providers that already carried this concept under other names keep those names working as deprecated aliases feeding the same field:
workingDiron@mastra/dockerand@mastra/apple-container, andworkdiron@mastra/modal. When both the alias andworkingDirectoryare set,workingDirectorywins. Use absolute paths: the value is passed to the provider as-is, so~and environment variables like$HOMEare not expanded (except where a provider documents expansion, such asLocalSandboxexpanding~).Also in: @mastra/agentcore@0.5.0, @mastra/apple-container@0.5.0, @mastra/blaxel@0.9.0, @mastra/cloudflare-sandbox@0.3.0, @mastra/daytona@0.10.0, @mastra/docker@0.7.0, @mastra/e2b@0.11.0, @mastra/modal@0.6.0, @mastra/platform-workspace@1.5.0, @mastra/railway@0.8.0, @mastra/vercel@1.5.0
Patch Changes
-
Update provider registry and model documentation with latest models and providers (
3910c77) -
Fixed
SlashCommandChannelHandler,SlashCommandChannelHandlerConfig, andSlashCommandEventnot being exported from@mastra/core/channels. Standalone slash-command handlers can now be typed directly instead of reaching throughChannelHandlers['onSlashCommand']. (#22814)import type { SlashCommandChannelHandler } from '@mastra/core/channels'; const onSlashCommand: SlashCommandChannelHandler = async (event, defaultHandler) => { if (event.command === '/help') { await event.channel.post('Available commands: /help'); return; } await defaultHandler(); };
-
Fixed approval event delivery for function-form
toolDisplayin streaming channels. A function-formtoolDisplaynow receivesapprovalevents whenstreaming: true, matching static mode. Return{ kind: 'post', message }to replace the built-in approval card;undefined, blank, orstreamresults fall back to the built-in card so the approval stays actionable. (#22832) -
Exported the validateToolOutput helper from @mastra/core/tools so integrations can validate tool results against a schema and produce the same structured validation error as createTool. (#22779)
-
Update README to include accurate, up-to-date information (#22858)
Also in: @mastra/acp@0.4.1, @mastra/agent-browser@0.5.2, @mastra/agent-builder@1.1.16, @mastra/agentcore@0.5.0, @mastra/agentfs@0.2.1, @mastra/ai-sdk@1.10.1, @mastra/apple-container@0.5.0, @mastra/archil@0.2.1, @mastra/arize@1.3.13, @mastra/arthur@0.4.13, @mastra/astra@1.1.1, @mastra/auth@1.1.3, @mastra/auth-auth0@1.2.3, @mastra/auth-better-auth@1.1.5, @mastra/auth-clerk@1.2.4, @mastra/auth-cloud@1.2.5, @mastra/auth-firebase@1.1.2, @mastra/auth-google@0.1.2, @mastra/auth-neon@0.3.2, @mastra/auth-okta@0.2.2, @mastra/auth-studio@1.3.5, @mastra/auth-supabase@1.1.4, @mastra/auth-workos@1.6.5, @mastra/azure@0.3.1, @mastra/blaxel@0.9.0, @mastra/braintrust@1.3.10, @mastra/brightdata@0.3.1, @mastra/browser-firecrawl@0.2.2, @mastra/browser-viewer@0.2.3, @mastra/chroma@1.1.3, @mastra/claude@0.3.1, @mastra/clickhouse@1.16.1, @mastra/client-js@1.43.0, @mastra/cloudflare@1.6.4, @mastra/cloudflare-d1@1.3.2, @mastra/cloudflare-sandbox@0.3.0, @mastra/code-sdk@1.6.0, @mastra/codemod@1.1.2, @mastra/convex@1.5.6, @mastra/couchbase@1.1.2, @mastra/cursor@0.3.1, @mastra/datadog@1.4.5, @mastra/daytona@0.10.0, @mastra/deepeval@0.1.7, @mastra/deployer@1.64.0, @mastra/deployer-cloud@1.64.0, @mastra/deployer-cloudflare@1.2.23, @mastra/deployer-netlify@1.2.23, @mastra/deployer-sandbox@0.3.8, @mastra/deployer-vercel@1.2.23, @mastra/docker@0.7.0, @mastra/dsql@1.3.4, @mastra/duckdb@1.6.4, @mastra/dynamodb@1.3.3, @mastra/e2b@0.11.0, @mastra/e2b-desktop@0.1.1, @mastra/editor@0.14.3, @mastra/elasticsearch@1.4.1, @mastra/elysia@0.1.4, @mastra/evals@1.10.0, @mastra/express@1.5.8, @mastra/factory@0.12.0, @mastra/fastembed@1.3.1, @mastra/fastify@1.5.8, @mastra/files-sdk@0.3.1, @mastra/gcs@0.3.3, @mastra/github-signals@0.4.0, @mastra/google-cloud-pubsub@1.1.3, @mastra/google-drive@0.2.1, @mastra/hono@1.7.6, @mastra/inngest@1.8.9, @mastra/isolated-vm@0.1.2, @mastra/koa@1.7.8, @mastra/laminar@1.3.15, @mastra/lance@1.3.2, @mastra/langfuse@1.5.4, @mastra/langsmith@1.3.15, @mastra/libsql@1.22.3, @mastra/livekit@0.3.1, @mastra/loggers@1.3.1, @mastra/mcp@1.17.3, @mastra/mcp-docs-server@1.2.23, @mastra/mcp-registry-registry@1.1.2, @mastra/memory@1.28.2, @mastra/mesa@0.2.1, @mastra/modal@0.6.0, @mastra/mongodb@1.18.5, @mastra/mssql@1.7.4, @mastra/mysql@0.8.5, @mastra/nestjs@0.2.23, @mastra/next@0.2.22, @mastra/observability@1.17.5, @mastra/openai@1.1.1, @mastra/opencode@0.1.23, @mastra/opensearch@1.1.1, @mastra/oracledb@0.2.2, @mastra/otel-bridge@1.5.5, @mastra/otel-exporter@1.3.13, @mastra/parallel@0.1.1, @mastra/perplexity@0.2.1, @mastra/pg@1.22.3, @mastra/pinecone@1.1.1, @mastra/platform-workspace@1.5.0, @mastra/playground-ui@52.0.0, @mastra/posthog@1.3.7, @mastra/qdrant@1.1.3, @mastra/quickjs@0.1.1, @mastra/rag@2.6.1, @mastra/railway@0.8.0, @mastra/react@1.4.10, @mastra/redis@1.4.3, @mastra/redis-streams@0.4.1, @mastra/s3@0.6.2, @mastra/s3vectors@1.1.2, @mastra/schema-compat@1.3.8, @mastra/sentry@1.2.15, @mastra/server@1.64.0, @mastra/slack@1.6.3, @mastra/spanner@1.6.4, @mastra/stagehand@0.3.4, @mastra/tanstack-start@0.2.22, @mastra/tavily@1.1.2, @mastra/telegram@0.1.1, @mastra/temporal@0.4.2, @mastra/turbopuffer@1.2.1, @mastra/turso@0.1.3, @mastra/upstash@1.4.4, @mastra/valkey@0.2.1, @mastra/valkey-streams@0.5.1, @mastra/vectorize@1.1.2, @mastra/vercel@1.5.0, @mastra/voice-aws-nova-sonic@0.2.2, @mastra/voice-azure@0.12.1, @mastra/voice-cloudflare@0.13.2, @mastra/voice-deepgram@0.13.1, @mastra/voice-elevenlabs@0.13.1, @mastra/voice-gladia@0.13.1, @mastra/voice-google@0.14.2, @mastra/voice-google-gemini-live@0.14.8, @mastra/voice-inworld@0.4.2, @mastra/voice-mistral@0.1.1, @mastra/voice-modelslab@0.2.1, @mastra/voice-murf@0.13.1, @mastra/voice-openai@0.13.1, @mastra/voice-openai-realtime@0.13.8, @mastra/voice-playai@0.13.1, @mastra/voice-sarvam@1.1.1, @mastra/voice-speechify@0.14.1, @mastra/voice-xai-realtime@0.2.8, @mastra/voyageai@0.4.1
-
Fixed per-tool
requireApprovalfunctions (needsApprovalFn) receiving no context on durable agents andagent.network(). They now get the same{ requestContext, workspace }second argument asstream()/generate(), so approval logic that reads the request context works consistently. On durable agents the request context is restored from the persisted run snapshot when the check runs in another process or after a resume. Fixes #22491 (#22841) -
Fixed tool observability helpers to emit correlated logs and child spans during agent execution. (#22887)
-
Fixed the scheduler polling storage every 10 seconds in apps that never create a schedule, which kept Railway/Neon-style deployments from scaling to zero. The scheduler now runs a single
listSchedules()check at boot and only starts polling when a schedule exists or is created (or whenscheduler: { enabled: true }/MASTRA_WORKERS=scheduleropts in explicitly), and worker processes learn about schedules created by the API process through the shared PubSub backend instead of constant polling. Also fixed deferred notifications sent from aworkers: falseAPI process never being dispatched: that process now registers the dispatcher schedule so a standalone worker can run it. (#22909) -
Fixed signals sent after DurableAgent recovery so they are drained by the resumed run. (#22781)
-
Fixed durable agent run recovery losing the fallback model list. After a process restart, DurableAgent.recover() now restores the live fallback models with the ids the run was prepared with, so recovered runs keep using custom or dynamically resolved fallback model instances instead of failing or falling back to models rebuilt from serialized config. Fixes #22594. (#22860)
-
runEvalsnow honours the trajectory contract in both gate loops. A scorer created withtype: 'trajectory'is typed as receivingoutput: Trajectory, and thescorers.trajectorypath already resolved one and threadedexpectedTrajectory; the top-levelgatesloop and the per-turnturns[].gatesloop passed the raw target output and noexpectedTrajectory, so such a gate scored 0 on every item as soon as it read a trajectory field. Workflow targets resolve the trajectory from step results, matching the scorer path, instead of being handed the workflow's own result. Gate failures are also no longer silent: a throwing gate still scores 0, but the cause is logged with the gate id instead of being discarded by a barecatch. (#22903) -
Fixed AgentController dropping streamed assistant text and reasoning after page reload. Text and reasoning deltas that arrive without a seeded part (for example after a mid-stream step rotation) are now folded into the message instead of being silently discarded. Fixes #22712 (#22775)
-
Fixed LocalSandbox native isolation being unable to open /dev/null, which broke git, ssh, and shell redirections (e.g.
2>/dev/null) inside the sandbox. On Linux, the Bubblewrap backend now mounts a fresh /dev with standard device nodes, emitted after all configured binds so existing workarounds likereadOnlyPaths: ['/dev']no longer shadow it. On macOS, the Seatbelt profile now allows writing to the standard device nodes (/dev/null, /dev/zero, /dev/random, /dev/urandom, /dev/tty). Fixes #22702 (#22791) -
Fixed durable agent traces being polluted by output-stream processor spans. The durable per-chunk processor pipeline ran without a tracing context, so every
output stream processorspan exported with no parent. Span stores that label a trace by its newest root row then showed a processor id instead of the agent. (#22677)- Output-stream processor spans now nest under the run's
agent runspan. - Tool-call chunks and resumed runs parent their processor spans the same way.
- The tool-call pipeline ends its processor spans right after each chunk, so none stay open.
- Callers without a tracing context no longer create processor spans, so orphan trace roots can never appear.
Fixes #22602
- Output-stream processor spans now nest under the run's
-
Fixed plan approvals so mode changes resume the original agent run. (#22476)
-
Fixed durable agent output processors receiving an empty request context, including after server restarts. (#22327)
-
Fixed durable agents dropping already-streamed assistant text from memory when a run is aborted mid-stream. The partial response was visible in the live stream and in the onAbort callback, but disappeared after a reload or memory recall — only the user message remained. Aborted runs now persist the partial assistant message to memory, matching the regular agent's behavior. Fixes #22593 (#22872)
-
Fixed background tasks advertising the
_backgroundoverride to every tool. Previously, enablingbackgroundTaskson the Mastra instance injected the_backgroundfield into every tool's input schema and listed every tool as background-eligible in the system prompt, even when neither the agent nor the tool opted in. Now only tools that are actually background-eligible — via the agent'sbackgroundTasks.toolsconfig or the tool's ownbackground: { enabled: true }— advertise the override, matching the runtime dispatch behavior. This removes roughly 2,000 characters of prompt overhead per ineligible tool and stops the model from being told it can background tools it cannot. Fixes #22724. (#22777) -
Fixed approval resumes when Agent Controller uses in-memory storage. (#22476)
-
Fixed workspace skill discovery silently reporting zero skills when the workspace filesystem is mis-wired. Invalid-argument errors (Node
ERR_INVALID_ARG*, e.g. a non-string path handed to the skill source) now surface from refresh() instead of being logged as an inaccessible skills path warning. Genuine access failures and network errors keep the warn-and-continue behavior. Closes #22639 (#22823) -
Fixed UnixSocketPubSub accepting unbounded inbound frames. Added a
maxInboundFrameBytesoption (default 64 MiB); a connection that sends a larger frame, or an unterminated partial frame beyond that size, is disconnected, and partial frames are buffered compactly regardless of how they are fragmented, so a single peer can no longer exhaust broker memory. Fixes #22376 (#22882)import { UnixSocketPubSub } from '@mastra/core/events'; const pubsub = new UnixSocketPubSub('/tmp/mastra.sock', { maxInboundFrameBytes: 8 * 1024 * 1024, // 8 MiB });
-
Removed the vulnerable @ai-sdk/provider-utils@3.x dependency (CVE-2026-8769 / GHSA-866g-f22w-33x8) from @mastra/core. The helpers it supplied are now sourced from the patched provider-utils 4.x line already installed, so security audits no longer flag @mastra/core and its dependents. AI SDK v5 model compatibility is unchanged. Fixes #22592. (#22790)
-
Fixed
listResolved()on versioned storage domains issuing one version query per listed entity.@mastra/coreadds an overridablegetVersions(ids)method thatlistResolved()uses to fetch all active versions in a single batch; adapters that don't override it keep their previous per-id behavior.@mastra/pgand@mastra/libsqloverride it for the agents and skills domains with a singleWHERE id IN (...)query. Fixes #22524 (#22828)Also in: @mastra/libsql@1.22.3, @mastra/pg@1.22.3
-
Fixed observability signals from Studio (mastra dev) being tagged with environment: production. Runs started through mastra dev now resolve to development unless an explicit environment is configured. Fixes #21941 (#22734)
-
Record TripWire aborts on workflow-path PROCESSOR_RUN spans as span errors with the structured
tripwireAbortattribute (reason, retry, metadata), matching the legacy processor-runner path. Previously these spans ended like successful runs with onlyoutput.tripwire, dropping the retry flag and error info. (#22350) -
Fixed onDelegationComplete reporting successful sub-agent runs when the finish reason is error. (#22483)
-
Fixed scheduled workflows disappearing from Studio's Schedules tab for dynamically created workflows. Dynamic workflow definitions now persist their schedule configuration, so schedules are re-declared after a restart instead of being deleted as orphans. Schedules of dynamic workflows that fail to load are also kept instead of being swept. Fixes #22756 (#22778)
Also in: @mastra/libsql@1.22.3, @mastra/mongodb@1.18.5, @mastra/mssql@1.7.4, @mastra/mysql@0.8.5, @mastra/pg@1.22.3, @mastra/spanner@1.6.4
-
Fixed span metadata values being silently erased by keys whose value is undefined. Values extracted via requestContextKeys (for example a threadId set on a RequestContext) now reach exported spans even when the agent has no memory configured, so exporters like Arize can group traces into sessions again. Keys passed in tracingOptions.metadata with undefined values no longer remove values the span already has; keys with real values still take precedence. Fixes #22597. (#22742)
Also in: @mastra/observability@1.17.5
-
Remove
CHANGELOG.mdfrom distributed npm files resulting in reduced package size (#22737)Also in: @mastra/acp@0.4.1, @mastra/agent-browser@0.5.2, @mastra/agent-builder@1.1.16, @mastra/agentcore@0.5.0, @mastra/agentfs@0.2.1, @mastra/ai-sdk@1.10.1, @mastra/apple-container@0.5.0, @mastra/archil@0.2.1, @mastra/arize@1.3.13, @mastra/arthur@0.4.13, @mastra/astra@1.1.1, @mastra/auth@1.1.3, @mastra/auth-auth0@1.2.3, @mastra/auth-better-auth@1.1.5, @mastra/auth-clerk@1.2.4, @mastra/auth-cloud@1.2.5, @mastra/auth-firebase@1.1.2, @mastra/auth-google@0.1.2, @mastra/auth-neon@0.3.2, @mastra/auth-okta@0.2.2, @mastra/auth-studio@1.3.5, @mastra/auth-supabase@1.1.4, @mastra/auth-workos@1.6.5, @mastra/azure@0.3.1, @mastra/blaxel@0.9.0, @mastra/braintrust@1.3.10, @mastra/brightdata@0.3.1, @mastra/browser-firecrawl@0.2.2, @mastra/browser-viewer@0.2.3, @mastra/chroma@1.1.3, @mastra/claude@0.3.1, @mastra/clickhouse@1.16.1, @mastra/client-js@1.43.0, @mastra/cloudflare@1.6.4, @mastra/cloudflare-d1@1.3.2, @mastra/cloudflare-sandbox@0.3.0, @mastra/code-sdk@1.6.0, @mastra/codemod@1.1.2, @mastra/convex@1.5.6, @mastra/couchbase@1.1.2, @mastra/cursor@0.3.1, @mastra/datadog@1.4.5, @mastra/daytona@0.10.0, @mastra/deepeval@0.1.7, @mastra/deployer@1.64.0, @mastra/deployer-cloud@1.64.0, @mastra/deployer-cloudflare@1.2.23, @mastra/deployer-netlify@1.2.23, @mastra/deployer-sandbox@0.3.8, @mastra/deployer-vercel@1.2.23, @mastra/docker@0.7.0, @mastra/dsql@1.3.4, @mastra/duckdb@1.6.4, @mastra/dynamodb@1.3.3, @mastra/e2b@0.11.0, @mastra/e2b-desktop@0.1.1, @mastra/editor@0.14.3, @mastra/elasticsearch@1.4.1, @mastra/elysia@0.1.4, @mastra/evals@1.10.0, @mastra/express@1.5.8, @mastra/factory@0.12.0, @mastra/fastembed@1.3.1, @mastra/fastify@1.5.8, @mastra/files-sdk@0.3.1, @mastra/gcs@0.3.3, @mastra/github-signals@0.4.0, @mastra/google-cloud-pubsub@1.1.3, @mastra/google-drive@0.2.1, @mastra/hono@1.7.6, @mastra/inngest@1.8.9, @mastra/isolated-vm@0.1.2, @mastra/koa@1.7.8, @mastra/laminar@1.3.15, @mastra/lance@1.3.2, @mastra/langfuse@1.5.4, @mastra/langsmith@1.3.15, @mastra/libsql@1.22.3, @mastra/livekit@0.3.1, @mastra/loggers@1.3.1, @mastra/mcp@1.17.3, @mastra/mcp-docs-server@1.2.23, @mastra/mcp-registry-registry@1.1.2, @mastra/memory@1.28.2, @mastra/mesa@0.2.1, @mastra/modal@0.6.0, @mastra/mongodb@1.18.5, @mastra/mssql@1.7.4, @mastra/mysql@0.8.5, @mastra/nestjs@0.2.23, @mastra/next@0.2.22, @mastra/observability@1.17.5, @mastra/openai@1.1.1, @mastra/opencode@0.1.23, @mastra/opensearch@1.1.1, @mastra/oracledb@0.2.2, @mastra/otel-bridge@1.5.5, @mastra/otel-exporter@1.3.13, @mastra/parallel@0.1.1, @mastra/perplexity@0.2.1, @mastra/pg@1.22.3, @mastra/pinecone@1.1.1, @mastra/platform-workspace@1.5.0, @mastra/playground-ui@52.0.0, @mastra/posthog@1.3.7, @mastra/qdrant@1.1.3, @mastra/quickjs@0.1.1, @mastra/rag@2.6.1, @mastra/railway@0.8.0, @mastra/react@1.4.10, @mastra/redis@1.4.3, @mastra/redis-streams@0.4.1, @mastra/s3@0.6.2, @mastra/s3vectors@1.1.2, @mastra/schema-compat@1.3.8, @mastra/sentry@1.2.15, @mastra/server@1.64.0, @mastra/slack@1.6.3, @mastra/spanner@1.6.4, @mastra/stagehand@0.3.4, @mastra/tanstack-start@0.2.22, @mastra/tavily@1.1.2, @mastra/telegram@0.1.1, @mastra/temporal@0.4.2, @mastra/turbopuffer@1.2.1, @mastra/turso@0.1.3, @mastra/upstash@1.4.4, @mastra/valkey@0.2.1, @mastra/valkey-streams@0.5.1, @mastra/vectorize@1.1.2, @mastra/vercel@1.5.0, @mastra/voice-aws-nova-sonic@0.2.2, @mastra/voice-azure@0.12.1, @mastra/voice-cloudflare@0.13.2, @mastra/voice-deepgram@0.13.1, @mastra/voice-elevenlabs@0.13.1, @mastra/voice-gladia@0.13.1, @mastra/voice-google@0.14.2, @mastra/voice-google-gemini-live@0.14.8, @mastra/voice-inworld@0.4.2, @mastra/voice-mistral@0.1.1, @mastra/voice-modelslab@0.2.1, @mastra/voice-murf@0.13.1, @mastra/voice-openai@0.13.1, @mastra/voice-openai-realtime@0.13.8, @mastra/voice-playai@0.13.1, @mastra/voice-sarvam@1.1.1, @mastra/voice-speechify@0.14.1, @mastra/voice-xai-realtime@0.2.8, @mastra/voyageai@0.4.1
@mastra/browser-viewer@0.2.3
Patch Changes
- Fixed the browser viewer reporting no URL and no tabs.
getCurrentUrl()andgetBrowserState()onBrowserVieweralways returnednullbecause they were never wired to the internal tab state. The viewer now returns the current URL and the list of open tabs. Fixes #22539. (#22624)
@mastra/clickhouse@1.16.1
Patch Changes
-
Corrected the minimum supported @mastra/core version to match the APIs used by this store. (#22564)
Also in: @mastra/cloudflare-d1@1.3.2, @mastra/dsql@1.3.4, @mastra/duckdb@1.6.4, @mastra/dynamodb@1.3.3, @mastra/elasticsearch@1.4.1, @mastra/mssql@1.7.4, @mastra/oracledb@0.2.2, @mastra/redis@1.4.3, @mastra/spanner@1.6.4, @mastra/valkey@0.2.1
-
Added
reviewStatussupport to observability feedback storage so feedback can be listed by review state and marked as reviewed. Existing rows default toneeds-review; updates are append-only (a new row is inserted and reads useFINAL). (#22805)const { feedback } = await storage.listFeedback({ filters: { reviewStatus: 'needs-review' } }); await storage.updateFeedbackReviewStatus({ feedbackId: feedback[0].feedbackId, reviewStatus: 'reviewed' });
@mastra/client-js@1.43.0
Minor Changes
-
Add host-injected trace signal management contracts and an OSS-owned Intelligence settings pane for custom signal configuration. Custom signal instructions use one task prompt field without a separate response-rules contract. (#21758)
<TraceIntelligenceProvider signalManagement={signalManagement}> <TraceIntelligenceEntityIndex {...indexProps} /> </TraceIntelligenceProvider>
Also in: @mastra/playground-ui@52.0.0
-
Added custom trace signal names and server-provided signal catalog types to Trace Intelligence responses. (#21758)
import type { ThemeEntitiesResponse } from '@mastra/client-js'; function signalLabels(response: ThemeEntitiesResponse) { return response.entities[0]?.signalCatalog?.map(signal => signal.label) ?? []; }
-
Added rolling-compatible Trace Intelligence entity index metadata types and an index-first list and compact view with controlled search, sorting, and view state. (#21758)
<TraceIntelligenceEntityIndex search={search} sort={sort} view={view} getEntityHref={entity => `/intelligence/entities/${entity.entityType}/${entity.entityId}`} />
Also in: @mastra/playground-ui@52.0.0
Patch Changes
- Added the optional
hasBrowserfield to the serialized agent response type. (#22789)
@mastra/code-sdk@1.6.0
Minor Changes
-
SandboxFilesystemaccepts a lazyworkdir— a resolver function awaited on the first file operation and memoized — for sandboxes whose workspace root is only knowable once the VM is running (repos clone into the VM's own home dir).basePathreports empty andresolveAbsolutePathreturns undefined until the root resolves; a failed resolution is not memoized, so the next operation retries. (#22065) -
Remove the sandbox reattach seam (
@mastra/code-sdk/agents/sandbox-reattach—registerSandboxReattach/reattachProjectSandbox) and the state-driven sandbox workspace branch ingetDynamicWorkspace(state.projectRepositoryId/sandboxId/sandboxWorkdir). Factory resolves session workspaces through its own sandbox callback; the UI-pushed sandbox coordinates in controller state were read by a code path that could no longer execute. ThesandboxId/sandboxWorkdir/worktreePathstate fields are removed from the state schema entirely — nothing reads them (the workdir is always live-resolved from the sandbox, and the sandbox id is the session id). Old clients still sending them are unaffected: unknown state keys are stripped on parse. (#22065) -
Enabled first-message thread title generation for all Mastra Code clients. (#22560)
Patch Changes
-
Improve internal observational-memory processing. (#22738)
Also in: @mastra/factory@0.12.0, @mastra/memory@1.28.2
-
Signed-in Factory accounts now get a clear, actionable error when no usable provider credential is available, instead of a silent failure. (#22721)
-
Hosted sessions no longer leak the host process's environment into the system prompt. The dynamic instructions builder drops its
process.cwd()fallback: a session without aprojectPathgets no working directory, no host git-branch probe, and loads no instruction files at all (project locations would resolve against the server's cwd and global locations against the server's homedir). Factory additionally blanks the SDK's default project identity seed (projectPath/projectName/gitBranchfrom the host's own checkout) so chat-only sessions show "(no workspace attached)" instead of the server's repo and branch; repo-backed sessions keep getting their real session workdir pinned by workspace resolution. (#22065)Also in: @mastra/factory@0.12.0
@mastra/daytona@0.10.0
Minor Changes
- An explicit
workingDirectoryoption skips the automatic working-directory probe; the probe still runs when the option is absent. (#22697)
@mastra/deployer@1.64.0
Patch Changes
- Fixed the browser screencast stream and session probe not finding workspace-level CLI browser providers. The server's browser stream
getToolsetnow falls back to the agent's workspace browser when no agent-level browser is configured. Fixes #22535 (#22789)
@mastra/dsql@1.3.4
Patch Changes
- Fixed memory thread and resource timestamps being written in the server's local timezone.
createdAtandupdatedAtare now stored as UTC, so both timestamp column variants hold the same instant regardless of where the process runs. (#22818)
@mastra/duckdb@1.6.4
Patch Changes
-
Add
reviewStatussupport to observability feedback storage: new column with migration (defaults toneeds-review), read/write mapping,reviewStatuslist filtering, andupdateFeedbackReviewStatusimplementation. (#22805)Also in: @mastra/pg@1.22.3
@mastra/e2b@0.11.0
Minor Changes
-
Added repository templates, so sandboxes start with a warm checkout (#22065)
createRepoTemplate()builds an E2B template with the repository already cloned and its setup command already run. Sessions then start from a prepared image instead of paying a cold clone and install.new E2BSandbox({ id: sessionId, template: createRepoTemplate({ getRepositoryAccess: async () => ({ cloneUrl: 'https://github.com/acme/widgets.git', authorization: { scheme: 'bearer', token: await mintInstallationToken() }, }), setupCommand: 'pnpm install', }), });
getRepositoryAccesssupplies the clone URL and, for private repositories, a short-lived credential. It returnsundefinedfromcreateRepoTemplate()when the accessor is absent, so a session with no repository needs no conditional at the call site. The credential authenticates the head lookup and the build's clone through an in-shell auth header, reaching the template definition's environment but never the image filesystem. It's set asGH_TOKEN, the same variable a session installs before running setup, so a setup command behaves identically in both places.Only the first build ever blocks a start
There's one template per repository, setup command, and workdir, with the commit sha as a tag (
mastra-repo-<owner>-<repo>-<hash>:sha-<sha>). Without an explicitshathe template pins itself to the repository's current default-branch head at resolution time. When the head moves, the next sandbox boots immediately from the previous build while the new sha builds in the background, and runtime setup fast-forwards the checkout. A failed build falls back to the default template plus a runtime clone, so a broken build never wedges a session.Added
buildEnvfor setup commands that need credentialsRegistry tokens, private index URLs, and anything else the setup command needs at build time. Accepts a record or an async resolver. Values are part of the template's identity, so changing one produces a new template.
Added
refreshRepoTemplate()for warming templates ahead of timeThe same resolution the lazy start path performs, exposed standalone and awaited, so a cron or a merge-to-main handler can build the template before anyone opens a session.
Default template ships a current Node.js LTS with corepack enabled
The e2b base image carries Node 20.9.0, old enough that corepack-fetched package managers crash on it, so a setup command like
pnpm i && pnpm buildfailed out of the box. The default mountable template now installs a pinned Node 24.20.0 over the stale runtime and enables corepack with the download prompt disabled, sopnpmandyarnresolve to whatever a repository'spackageManagerfield pins. Repo templates build on the default mountable template, so they inherit the working toolchain. Pick a different release with the newnodeVersionoption:createDefaultMountableTemplate({ nodeVersion: '22.23.2' });
The version is exact and identity-bearing: changing it builds a new template, so a version change can never silently reuse a build at the old runtime. Existing default and repo templates rebuild once on first use after upgrading.
Machine resources:
cpuCountandmemoryMBThe built template's sandboxes get exactly that machine size. Resources are part of the template's identity — hashed into the template name alongside the repository, setup command, and build env — so a resize builds a new template instead of silently reusing one built at the old size. Absent options normalize to the SDK defaults (2 vCPU, 1024 MB). When a repo template's build fails and the sandbox degrades to the default mountable template, the default is built at the requested size too, so a 2 GB session's setup never lands in a 1 GB fallback and runs out of memory.
new E2BSandbox({ id: sessionId, template: createRepoTemplate({ ...ctx, memoryMB: 2048, cpuCount: 4 }), });
-
createRepoTemplatenow runs each command (clone, fetch, checkout, and each setup command) as its own cached build step, andsetupCommandaccepts an array. A newworkingDirectoryoption sets the cwd for the build and for sandboxes created from the template; the repository is cloned to<workingDirectory>/<repo>. When omitted, the clone lands in the base image's working directory instead of$HOME. (#22698)createRepoTemplate({ getRepositoryAccess, setupCommand: ['pnpm i', 'pnpm build'], workingDirectory: '/workspace', });
Also in: @mastra/platform-workspace@1.5.0
Patch Changes
-
Repo templates now write
.mastra-sandbox/setupbeside the checkout as their last build step. It containssha256:<digest of the setup commands>, so a sandbox booted from the template can tell that this setup already ran. (#22837)Also in: @mastra/platform-workspace@1.5.0
-
Repository templates now clone with
--depth=1 --single-branch, so template builds transfer less history. (#22840)Also in: @mastra/platform-workspace@1.5.0
-
Fixed repo templates silently degrading to a repo-less template on hosts without a
gitbinary (deployed Mastra servers), which made every session cold-clone at runtime. GitHub (github.com) clone URLs now resolve the default-branch head through the GitHub REST API; other hosts keep usinggit ls-remote. (#22833)Also in: @mastra/platform-workspace@1.5.0
@mastra/editor@0.14.3
Patch Changes
- Preserved tool schemas when applying stored descriptions. (#22459)
@mastra/evals@1.10.0
Minor Changes
-
Add
@mastra/evals/vitestfor runningrunEvalsevaluations as Vitest tests. (#22665)expectEvals/expectEvalfail the test when the eval doesn't pass.- Optional custom matchers (
toHaveVerdict,toHaveScoreAbove,toHaveScoreBelow,toPassGates,toPassThresholds) via@mastra/evals/vitest/setup. MastraEvalsReporterprints per-test scores in the runner output.
import { test } from 'vitest'; import { expectEvals } from '@mastra/evals/vitest'; test('capitals agent answers with the expected city', { timeout: 60_000 }, async () => { await expectEvals({ target: capitalsAgent, data: [{ input: 'What is the capital of France?', groundTruth: 'Paris' }], gates: [containsGroundTruth], }).toPass(); });
@mastra/factory@0.12.0
Minor Changes
-
Attention now rides the project feed stream: an automation failure, a proposal parked for approval, an approval, a dismissal, a retry, a supersede or a work-item deletion reaches every open page as it happens, and the attention list falls back to polling only while its stream is down. (#22604)
Marking your own list read stays local — a read receipt changes nobody else's view, so it is not broadcast.
-
Added
sandboxStart: 'eager' | 'lazy'toMastraFactoryConfig.'eager'starts a session's sandbox as soon as its workspace is first resolved instead of on the agent's first command. Defaults to'lazy'. (#22577)new MastraFactory({ sandbox: ctx => new PlatformSandbox({ id: ctx.sessionId }), sandboxStart: 'eager', });
-
Removed the automatic sandbox snapshot Factory took after every agent turn. (#22846)
PlatformSandbox.destroy()on E2B now only kills the sandbox instead of first asking the platform to delete a recovery checkpoint.Also in: @mastra/platform-workspace@1.5.0
-
BREAKING:
sandboxis now a callback that constructs the session's sandbox (#22065)// Before — no longer accepted sandbox: { machine: new RailwaySandbox({ apiToken }), workdir: '/workspace', maxSandboxes: 4 } // After sandbox: ctx => new E2BSandbox({ id: ctx.sessionId })
A factory still configured with the old options object fails at
prepare()with a message showing the replacement:machinebecomes the provider instance you construct inside the callback,workdiris gone (remote providers clone into the VM's home directory, local providers use their ownworkingDirectory), andmaxSandboxesis gone with the fleet. Omitsandboxentirely to run without sandboxes.ctx.getRepositoryAccessresolves the session repository's clone URL plus a fresh short-lived credential (undefinedwhen the session has no repository), so providers can authenticate work such as private-repo template builds.Session sandboxes now boot lazily at the first real command instead of being provisioned up front. The sandbox fleet (pooling, budgets, reattach/revival, base checkpoints) is deleted, and the
/ensureendpoint and the session UI's "preparing sandbox" step go with it — opening a thread provisions nothing. To check whether a sandbox is configured, readsandboxEnabledfromGET /web/github/status.A failing setup command no longer wedges the session. The first failure surfaces loudly in the tool result that triggered it, then later starts skip the known-bad command — the clone and branch checkout still run, so the agent can repair or rerun setup itself. Infrastructure failures (clone, checkout, transport) keep failing hard and retry in full.
Existing databases keep the fleet-era tables and columns as untouched orphans; dropping them is a manual operation.
-
Session start checks for the
.mastra-sandbox/setupmarker beside the checkout and skips the setup command when the marker holds the sha256 digest of the project's current setup command. Sandboxes booted from a warm repo template carry the marker already; setup runs once when it is missing or stale and writes the marker afterwards. (#22837) -
Runs started by the Factory no longer stall without appearing in Needs attention. (#22530)
A run that writes a plan used to suspend inside its thread and wait forever: the card said Building, nothing built, and no error appeared anywhere.
Added: an Auto-approve plans switch on the board
Find it in the board's automation settings, beside Auto-start runs. Off by default, which is what runs already did — except a plan nobody is watching now surfaces in Needs attention instead of hanging. On, the Factory answers the plan itself and the run carries the item through to Done. An agent that keeps re-planning is stopped after three approvals and handed to a person.
Fixed: who a parked plan waits for
With the switch off, where a parked plan goes depends on who started the run. A plan on a rule-started run escalates through the rule's own decision, the record Needs attention is built on. A plan on a run a person started keeps waiting for that person, because that pause is the point. With the switch on, the Factory answers both.
Fixed: two smaller holes on the same path
An agent asking to move its own card no longer parks the run behind an approval prompt nobody is watching; the rules engine still governs every move. And a failure that can never succeed on a retry stops burning attempts before it reaches someone.
-
Board lanes now mean engagement: a card enters a working lane only when a run starts on it or a person moves it there, and resting a card takes the Factory's hand off it. (#22531)
Every GitHub issue and pull request arrives in Intake. Trust moved out of the column layout and onto the card: arrivals are stamped with whether the Factory may pick them up on its own, an External mark shows cards the execution gate treats as externally authored, and a card whose run the Factory would start shows that as a suggestion you can release with a click. Reviewing means a review is running — before, a maintainer's pull request was born there with nothing reviewing it.
Consent follows the same line. A person's drag into a working lane hands the Factory the work; any entry into Intake, Done or Canceled takes it back, whoever rested the card — a verdict, a mirrored close, a drag. The close-out run a resting transition queued still fires, pre-approved by the transition that committed it. An external event can no longer pull a rested card back into a working lane or start a run on it without a person's consent, and a card from an author without write access never self-starts — even armed, even with auto-run on. A GitHub card missing its trust stamp — created before stamps existed — fails closed and asks too. The reconcile sweep keeps the stamp current in both directions: it backfills missing stamps and withdraws trust from authors whose write access was revoked, each within one sweep cycle (a few minutes by default); the Factory's own pull requests count as trusted through their authorship.
A card parked in Intake offers Resume as its primary action, re-entering the deepest seat it used, and asking the card's agent in chat to resume does the same through the governed transition. Dragging a card out no longer opens a session just to say so: the stop notice reaches whichever session is live on the card, or nobody. A run landing its card in a lane no longer dispatches a second run.
-
A Factory run waiting on any answer now surfaces instead of parking silently. (#22649)
Fixed: questions stalled the same way plans used to
The plan gate covered
submit_planonly. A run that asked a question throughask_userstill stalled with the card saying Building. Any tool suspension on an unattended run now lands in Needs attention as "Agent is waiting for an answer".Unchanged: pauses that belong to a person
Person-started runs are untouched — their pauses wait for the person reading them. Auto-approved plans stay the only pause the Factory answers itself, because a question has no approvable default.
-
Approving a proposed run now happens in the attention inbox instead of sending someone to the Rules page. (#22709)
A queue of proposals is a handful of decisions repeated, not a list of distinct ones. A rules engine proposes the same run for every card it matches, so fifty rows reading
invokeSkill · triagesaid nothing that "32 triage runs" does not. The queue sits grouped by role in a panel above the timeline, collapsed, one line per shape; expanding a group names the work item each proposal is for, so a row finally says what it would start. The banner that only counted the queue is gone, and the sidebar popover's approval link opens the inbox.A group can be dismissed whole, behind a confirm step — the way out of a queue nobody wants. There is deliberately no matching "run all": that would bill dozens of agent runs from one click, with no bulk route to make it atomic.
The queue says how much of itself it is showing. The count in the header is the true pending total; when more proposals exist than one page holds, the panel says how many of them loaded, and the per-group "oldest" timestamp is dropped rather than reporting the oldest of a partial page as the oldest of the queue.
An attention row says what landed as a badge —
mention,comment,failed— carrying the icon of its kind and dimming once read, instead of a coloured bead beside a sentence fragment, with the card as the row's title and the author ahead of the message. The sidebar popover scrolls through its preview again: its list had been capped by the popover's own height rather than the scroller's, which left the scroller measuring no overflow and the popover clipping the rows it could not show.The Rules page holds only what nothing else shows now that failures and approvals both land in attention — the full effect lifecycle, decisions with no work item, and the succeeded/dismissed history — so it leaves the Factory navigation and is reached from an attention row or global search.
-
Added a hands-off start for work items. (#22652)
How it works
Pick "Investigate hands-off" or "Build hands-off" in a card's menu instead of the plain start — restarts too: a card whose run already happened offers "Re-review hands-off" and a hands-off twin of its lane's run. "Prepare approval" has no twin — that run's outcome is a maintainer decision, which hands-off cannot remove. The run's parked plans are approved on your behalf, even while the project's Auto-approve plans switch stays off.
The grant sticks to the item, not the run, so the Factory's own follow-up runs on that card stay hands-off too. Other cards keep waiting for plan review, and a hands-off run that keeps re-planning still stops after three approvals.
-
Factory Overview now shows what landed in the repository, not only what moved on the board. (#22709)
A Latest commits section reads the connected repository's default branch newest-first, on the same day-rail the Activity and attention pages use: the branch tip carries a ring, everything behind it a filled bead, and each row gives the subject, its author, the short sha and when it landed, opening the commit on GitHub. A Factory with no repository linked says so rather than sitting on a skeleton.
A Factory whose board was busy all day but whose main branch has not moved now says so on the page that is supposed to answer that question, instead of sending someone to GitHub to find out. The section leans on
GET /web/github/projects/:id/commits, so it costs one rate-limited call per visit rather than a poll. -
Commenting on a work item now notifies everyone already in that discussion, not just the people it names. Participants land in a separate
activitytier ofGET /web/factory/projects/:id/attention, counted apart underactivityUnreadCountso the notification badge and sound stay reserved for mentions and failures. The attention inbox also refreshes while open now: comment-driven entries arrive over the feed stream, and the list polls every 5s for the rest. The sidebar popover asks the server for the badge tier (?tier=badge), so busy discussions can no longer crowd mentions and failures out of its five slots. (#22571) -
Rebuilt the Factory Overview at
/factories/:id/overviewaround what needed a person and what the Factory shipped, and gave board traffic its own page. (#22709)The page opens on a stage funnel for the work created in the selected window (7, 30 or 90 days), each card placed by the furthest stage it ever reached rather than by where it sits today.
- The saturated core is what got that far with nobody stepping in, the pale sheath what a person had to close. Moves made by Factory rules count as unattended, so the autonomy figures no longer bill automation to a person.
- Every loss peels off as its own hatched arm, billed to the column the work actually stopped in, so a drop keeps the thickness it cost instead of turning into whitespace.
- Each column carries its typical hold. Hovering one says how much of it ran hands-off, what it lost since the column before, and what landed as a merged pull request; hovering an arm says how much stopped there and whether it was called off, still holding the column, or left without a decision.
- The first rung reads Entered, not Intake: that board column also holds live GitHub and Linear candidates with no work item behind them, which the page cannot count.
- Pull requests the Factory reviewed are counted beside the funnel — a count and only a count, since whether they went on to merge is the team's decision rather than the Factory's work.
Why reach and not time-to-ship. On a real board almost nothing that lands in Done has passed through Execute and Review: Done is where cards get closed, not where work lands. A "shipped in this window, this fast, this hands-off" figure reads off that same history and cannot stand behind any of the three. Reach can, from the same records, so that is what the page reports.
Under the funnel: what is stalled, what is running now, the latest commits, and a preview of activity and of what needs you.
Board traffic has its own Activity page at
/factories/:id/activity, reading as a rail cut by day. It shows everything the Factory did, not only stage moves — the board's own stage history for the moves, and the audit trail for the runs started, commits, pushes and comments a move is not, two sources that never describe the same fact.- Each entry reads as a sentence: who acted, what they did, which card, hung off a coloured bead on one continuous rail.
- A card walked through several stages by one actor folds into a single chain instead of repeating its title, and neighbours saying the same thing about a different card become one sentence with those cards listed in a panel under it.
- Days are cut by a ruled heading and each row carries its minute on the right edge, so a screenful reads as prose down the middle rather than as a column of timestamps.
The attention inbox and the rule effects page now read on that same rail — cut by day, each row hanging off the mark of what it is (the kind of message, or the status of the effect) and carrying its time on the right edge, so the three pages are one surface instead of three list styles. The attention inbox also paginates like they do: older items load as the list is scrolled instead of waiting on a click.
Every page opens at its top. The data router carried the window scroll across navigations, so leaving a scrolled Overview landed on Activity halfway down it.
-
Work item comment feeds now update live instead of on a five-second poll: while a browser holds its feed stream, a new comment shows up the moment it lands, and a browser whose stream dropped falls back to the old poll until it reconnects. (#22570)
Delivery rides the factory's
pubsub, so reaching browsers across replicas takes a shared broker — the in-process default only serves readers held by the replica that took the write:import { MastraFactory } from '@mastra/factory'; import { RedisStreamsPubSub } from '@mastra/redis-streams'; export const factory = new MastraFactory({ pubsub: new RedisStreamsPubSub({ url: process.env.REDIS_URL }), });
-
Slack threads and work-item feeds are now one conversation seen from two windows. (#22641)
Slack → feed — a message starting with
aside, the human chatter the agent deliberately never answers, now lands as a comment on the card the thread created. A sender who has linked their Slack account is attributed to their Mastra user; an unlinked one is stored under their Slack identity and display name, so the thread stays complete either way.Feed → Slack — a comment written in the Factory feed is posted into the bound Slack thread, attributed as
**Name**: body(the app cannot post as the commenter).A Slack card is now keyed by workspace as well as thread:
ExternalWorkItemSourcegrows an optionalworkspaceId, andexternalSourceKey— the one builder cards and mirrored comments now share — includes it. A channel id and a messagetsonly identify a thread inside the workspace that issued them, so without it two workspaces running the same app could share a key: an aside could land on another tenant's card, or recover their comment instead of storing its own. Cards created before this ships keep their unscoped key, and the lookup still accepts that older form, so their threads keep syncing. Nothing writes it any more, so the set only shrinks.Both directions are create-only: comment edits and deletions do not propagate, and Slack edits and deletions never reach the feed because the adapter does not deliver those events to handlers. Mirroring stays best-effort — a failed post is logged, not retried — and it runs past the response: the comment is stored and its feed frame is out before the platform is called, so writing a comment never waits on Slack.
createCommenthands the in-flight mirror back asmirroredfor callers that need to observe it. Slack's own client is now given a 15s per-request timeout, which it did not have; its default retry policy can otherwise sit on a rate-limitedchat.postMessagefor about thirty minutes.A channel integration opts in by implementing the new
feedPublisherslot alongsidechannels:class SlackIntegration implements FactoryIntegration { channels(ctx: IntegrationContext) { return createSlackChannelsConfig({ ...deps, feed: ctx.feed }); } feedPublisher(ctx: IntegrationContext) { return new SlackFeedPublisher({ controller: ctx.controller }); } }
Patch Changes
-
Factory badges now follow the unified design-system
Badge: same soft corners, inset ring and size scale everywhere, and each badge names the color it wants rather than a mood. Provider access, model packs and the model picker keep their meaning — green for a working credential, blue for one that comes from the org or the environment — but they now read as one family instead of three slightly different pills. (#22640) -
The completion chime is lower and longer. It swells into a soft tail that rings out over about two and a half seconds, instead of the short ding that stopped dead almost as soon as it started. (#22566)
It is also much louder than the chime it replaces. If you leave the completion sound on, check your volume after this release.
-
Fixed issues and pull requests from outside the write-access circle asking for approval again at every lane after a person had already started them. Starting, dragging, or approving a run on such a card now carries that consent through the runs queued by the card's agent on its way to review. One gesture takes the card to a pull request instead of one click per lane. The same holds when a person creates a card straight into a working lane or moves it there through the API, and when the card's agent moves it on from a chat: the run queued by that move no longer waits for a click. Runs queued by a GitHub event on the card still ask first. An agent still cannot pull a rested external card back into work. A run pre-approved by an agent opens its session under the repository connector, never under the agent's id. (#22862)
-
Sessions on a remote sandbox with an absolute
workingDirectoryresolve the checkout at<workingDirectory>/<repo>without probing the VM. Sandboxes without one (or with a non-absolute one) keep the probe behavior. (#22698) -
Session start no longer runs
git pullon an existing checkout; it only clones when the repo is missing from the sandbox. Start-path phases (workspace.onStart,workspace.setup-marker,workspace.setup) now log their timings. (#22840) -
Reduced the GitHub integration's REST request volume. Collaborator permission lookups are cached for 30 minutes per repo and login, and the PR/issue reconcile sweeps default to hourly instead of every 5 minutes; event polling and webhooks remain the primary sync. Override the interval with
MASTRACODE_PLATFORM_GITHUB_RECONCILE_INTERVAL_MS(platform) orMASTRACODE_GITHUB_RECONCILE_INTERVAL_MS(direct), or the_PR_/_ISSUE_variants. (#22835) -
Improved Factory PR reviews by treating external CI status and issue links as advisory context while keeping independently verified defects blocking. (#22667)
-
Improved the board card status shown while a linked card is synced. Instead of "Filing a linked card…", cards now name the system they mirror, for example "Syncing GitHub pull request…" or "Couldn't sync GitHub issue". (#22883)
-
Factory panels now take their shadow and their chart ramp from the design system instead of redeclaring them, so they stay in step with every other surface when those tokens change. (#22713)
-
Session status (#22786)
- Fixed session status disagreeing between sidebar rows, board cards, and the open chat.
- Running, setting up, and waiting-on-you states now read the same after a reload and in every tab.
- Removed the per-browser "your turn" mark; a card waiting on a person is marked from the card itself, and a finished session with nothing waiting shows as idle.
Chat
- Fixed the favicon claiming the session awaits input while history is still loading.
- Allow steering or stopping a running session as soon as it is connected.
Done sound
- Plays once when a run watched in this tab ends.
-
A run started from a work item with comments shows its prompt as the collapsed skill row again, with the item's discussion in its own collapsible row beside it, instead of one raw message wide enough to break the page. Only that discussion may follow the skill envelope; anything else keeps the message raw. (#22551)
The Mastra Code terminal folds the same prompt into its skill row.
-
Factory now remembers a maintainer's acceptance of non-bug work. Triage classifies feature requests, questions and docs as needing a person's decision; before, that decision was checked again on every later agent move, so a card a maintainer had dragged into Planning still stalled when the plan agent tried to advance it to Build. (#22921)
- The first time a person moves a held card into Planning or Build, the acceptance is recorded on the work item. Later agent transitions along the working lanes proceed without a second gesture, and the gate only guards the exit from Intake/Triage. Cards accepted before this release are recognised by their stage, and pick up the record on their next human move.
- On acceptance, the GitHub
status: needs approvallabel is removed automatically (best effort; a label failure never blocks the move). - A held card on the board leads with the decision — Accept and plan, Accept and build, or Close — and says why it waits (
Feature request · needs your approval). Runs, re-runs and suggested runs on that card are withheld until it is accepted, so nothing advances it as a side effect. Bugs are never held.
-
Audit log range picking moves off the chart and onto a ruler below it. (#22709)
The chart is display-only. Marks outside the selected range fade instead of being framed by a drag rectangle, gridlines follow the day ticks and fade out top and bottom, and dashed guides mark the selected limits.
The ruler under it carries a single translucent lens. Drag its sides to resize, drag its body to slide the window; the day and time of each edge read above and below it. Selection is continuous down to the minute rather than snapped, so a window of a few minutes is as reachable as one of several days, and the exact range also reads out next to the event count. Arrow keys nudge an edge, Escape returns to the full range.
On narrow screens the lens gives way to 1h/6h/24h/7d chips. A full-width drag surface left no room for precise handles and blocked vertical scrolling.
The axis stops moving under the marks. It now spans everything loaded rather than the current category filter, so toggling a category no longer rescales it, and the chart holds a fixed height at any width instead of squashing its lanes on a narrow screen. Each category lane carries a faint dotted rule, so a mark reads as sitting on its lane and a chart with nothing to plot still shows its shape rather than going blank.
An empty log says so instead of drawing a chart over an invented seven-day window — filtering to a category with no events used to shift the axis onto dates where nothing had happened — and the empty states now say what is missing and how to get back.
-
Fixed authenticated workspace skill runs so tenant OAuth credentials remain available to agent and memory models. (#22721)
-
Improved Factory issue triage to label issues by domain in addition to confirmed direct @mastra/core bugs. Triage now selects domain labels such as Agents, Workflows, Memory, Observability (AI Telemetry), and RAG from where the change would land, applying several only when a change genuinely spans domains. (#22753)
-
The reconcile sweep now records author trust for cards it had stopped visiting, so a board whose cards reached Done or Canceled before trust was recorded gets its answers on the next sweep instead of never. The board's External mark reads a recorded answer instead of the absence of one, so a card nobody was ever asked about is no longer labelled an outside contribution. The execution-consent gate is unchanged: a card with no recorded answer still asks for a person before it starts a run. (#22644)
-
Fixed board cards for imported GitHub and Linear issues/PRs showing "just now" — cards now show how long ago the issue or PR was opened upstream instead of when the factory first saw it. (#22848)
-
Added
GET /web/github/projects/:id/commits(optionalbranch,limit), which lists recent commits for an installed repository. (#22709)It reads with the same installation token that already clones and pushes, rather than through
getInstallationOctokit: the Platform build answers that call with a stub carrying pull-request reads only, so anything reaching forrepos.*would have been undefined at runtime while the cast kept the compiler quiet. -
Fixed repository-local Factory skills not loading when the bundled skills exist. Factory now layers the consumer repo's src/mastra/public/factory-skills directory over the bundled Factory skills, so projects can add custom pipeline skills (or override built-in ones) without patching node_modules. The local skills root is also resolved correctly for the cwd variants used by mastra factory dev --dir src/mastra. Fixes #22707. (#22723)
-
Fixed "Linked card could not be filed: A work item cannot relate to itself" on Review cards. When GitHub polling re-observed a pull request that already had a card, the dispatcher tried to link the card to itself as its parent. (#22848)
-
Fixed Factory project sessions using organization model credentials. (#22741)
-
Improved how a session says what it is doing. A sidebar row now carries an activity rail down its left edge instead of a dot in its trailing slot: marks travel down the rail while a run is underway, in the setup colour while the sandbox is still starting, and settle into a slow breath once the session is waiting on you. A board card shows the same thing on its own border — a lit head running the outline while work is in flight, the whole outline lit once the card is waiting on you. (#22751)
Removed the marker for a session that is merely bound to a card: the card offers an Open session button instead, and the work item panel drops its dot for the same reason. Moving lifecycle off the row's trailing slot frees it — the actions menu no longer displaces the marker on hover, and a merged pull request keeps its badge.
-
Fixed the "ready — your turn" mark only going away when a session was opened from the sidebar. Opening the same thread through a board card, a deep link, or the attention inbox left the mark lit, and a run finishing in the very thread being read marked it as needing attention. Landing on a session's route — through any door — now dismisses its mark, and the open session never gets marked at all. The completion sound still plays for it, so a backgrounded tab still calls you back. (#22749)
-
Factory board cards now show live session status: idle, initializing, working, and ready. Cards and sidebar rows read the same status, so they always agree. A cloning workspace shows initializing, a running session shows working, and a finished run waiting for you shows ready. (#22748)
-
Improved Factory PR review to audit documentation changes on mastra-ai/mastra with the repository's
docs-auditskill, so docs changes are graded against the canonical authoring guidance instead of only general review judgement. (#22766) -
Fixed automated runs abandoning their session when a run is re-prepared (for example after a server restart). The run now lands back in the work item's existing session for that role instead of creating a replacement — so the session keeps its original owner instead of switching to whoever approved the run, and no orphaned sandbox is left behind. (#22410)
-
Fixed personal memory settings in the web app showing (and running) the default Gemini observer model after signing in with another provider. Signing in with a provider OAuth flow or saving a personal API key now seeds your unset observer and reflector models from that provider, matching the TUI onboarding behavior. (#22847)
-
Session comments panel (#22551)
The comments panel opens at half the height of the chat and grows with the conversation up to the full column, instead of opening full height around an empty feed. It morphs open from the workspace card. The composer is a flush bar at the bottom edge and takes focus as the panel opens. A comment that lands while you are watching rises into place. Editing a comment saves on Enter and keeps Shift+Enter for a new line, with Cancel and Save inside the bottom right of the field. The edit field grows with its text up to ten lines, then scrolls, with no resize handle. The workspace card's corners are concentric with the rows inside it. Session rows in the sidebar no longer open their hover details on a touch viewport, where the card could only appear behind the tap that already navigated away.
Board cards
A sent comment lands in the feed as soon as the server stores it, with no dimmed placeholder. A failed send keeps the draft and shows the error. Opening a card widens a copy of it over the card, every row anchored where the card had it, and pulls a tray out from beneath, a little narrower than the copy, so opening moves nothing you were about to click. Hovering a card no longer floats its full title over it; the open copy shows it whole.
The tray holds one timeline in time order: the item's runs, moves and comments, with the composer at the bottom. The description heads that stream in a block of its own, an Activity rule between them. The tray opens at its full height whatever the stream holds, waits for the description and the comments together, and lands them one after another, so nothing shifts once it loads.
Cards share a minimum height, with their bottom row pinned to the bottom edge. That row leads with one small button, the likeliest next click: the item's run, Retry after a failure, the suggested run while one waits, Open session while one runs. It lights up only while the card waits on you, to release a suggested run, retry a failure, or answer a session that asked. It goes quiet the moment a run is starting, so a lit button on the board always means your turn. A card in a lane leads with that lane's own run. The other buttons sit tucked under the first like pulled tabs, on the card and in its open copy alike. While a session runs, no rival run is offered beside it. The suggestion itself is a badge in the status row. The last worker sits at the right of the bottom row, the name before the picture, and the External badge sits at the right of its own row above. An expand icon appears beside the card's menu on hover, in the spot where the open copy puts Collapse. The copy names its source link with the item's icon and number instead of an arrow. The card's corners round a little more, concentric with the buttons in them, and the empty state of a column rounds its corners the same way.
Intake and the rest of the board
An intake candidate opens the same way, its run buttons in the copy and its description in the tray. Labels stay on one line that scrolls sideways instead of wrapping. A card near the bottom of the window opens its tray above the card instead of climbing to fit, and in the last column the tray slides left by its overflow while the copy stays over the card. The board dims under the open card, and a click on the dim closes it without pressing whatever sat underneath.
On a phone
The sheet opens straight onto the same timeline and composer, and hugs its content instead of opening at a fixed height.
@mastra/github-signals@0.4.0
Minor Changes
-
Added multi-PR GitHub signal tools and improved notification filtering. (#22407)
Agents can subscribe to multiple pull requests, unsubscribe from multiple pull requests, and unsubscribe from all tracked pull requests. The tool input shape now uses a
prsarray instead of the old single-PR top-level fields.Before:
{ "owner": "mastra-ai", "repo": "mastra", "number": 123 }After:
{ "prs": [{ "owner": "mastra-ai", "repo": "mastra", "number": 123 }] }Unsubscribe all:
{ "all": true }GitHub signal notifications now also filter repeated low-value bot comments such as skipped CodeRabbit reviews and bot status summaries.
@mastra/hono@1.7.6
Patch Changes
-
Fixed custom API routes registered with registerApiRoute failing with a 500 error ("Response body object should not be disturbed or locked") when server middleware read the request body (e.g. await c.req.json()) before the route handler ran. Request bodies now survive middleware reads via json(), text(), formData(), or the raw request. Fixes #22596 (#22776)
Also in: @mastra/server@1.64.0
@mastra/inngest@1.8.9
Patch Changes
- Fix durable tool execution on the Inngest engine running with no tracing context. The
extract-tool-callsstep now forwards the LLM step's exportedmodel_stepspan onto every tool-call input (matching @mastra/core's durable workflow), so each tool call creates a livetool_callspan with execution-time children (e.g.workspace_actionand client-tool spans) nested under the LLM call. The retroactivetool_callspan creation in the collect step was removed — it produced childless duplicate spans and redundant step-span end/tool-result chunk events already handled by the shared LLM mapping step. Fixes #19842. (#22279)
@mastra/langfuse@1.5.4
Patch Changes
- Map the root span's input/output to
langfuse.trace.input/langfuse.trace.outputso Langfuse traces carry trace-level input and output again. Previously the exporter only mapped input/output onto observations, leaving every trace's top-level input/output empty — which broke LLM-as-a-judge evaluators bound to Trace input/output and removed the request/response summary from the Langfuse trace view. User-facing behavior otherwise unchanged; existing trace name/tags/metadata mappings take the same precedence as before. (#22696)
@mastra/libsql@1.22.3
Patch Changes
-
Fixed local LibSQL vector corruption during concurrent writes. (#22834)
-
Fix the LibSQL vector filter's
$sizeoperator emitting invalid SQL: the builder misused the filter value as a parameter index, producing named references ($2,$5, …) that never matched the positional bindings.$sizenow binds through a standard?placeholder like every other operator, and the shared vector filter tests (supportsSize) are enabled for LibSQL accordingly. (#22752)
@mastra/livekit@0.3.1
Patch Changes
-
@mastra/livekit/workernow exportsMastraVoiceAgentandcreateMastraVoiceAgent(with theMastraVoiceAgentOptionsandMastraStreamOptionstypes). This is thevoice.AgentsubclasscreateLiveKitWorker()builds per session, so you can construct it yourself when you own thevoice.AgentSession— for example to test a Mastra-backed agent with@livekit/agents'voice.testingharness without speech-to-text, text-to-speech, or a running worker. (#22820)import { initializeLogger, voice } from '@livekit/agents'; import { createMastraVoiceAgent } from '@mastra/livekit/worker'; initializeLogger({ level: 'silent', pretty: false }); // required outside a LiveKit worker const session = new voice.AgentSession(); await session.start({ agent: createMastraVoiceAgent({ agent: supportAgent, memory: false }) }); const result = session.run({ userInput: 'What are your opening hours?' }); await result.wait(); result.expect.nextEvent().isMessage({ role: 'assistant' });
@mastra/loggers@1.3.1
Patch Changes
-
Fixed Errors logged under the
errorkey being recorded as an empty object. (#22913)Pino only applies its error serializer to the
errkey, and an Error'smessageandstackare non-enumerable. Sologger.warn('...', { error }), the convention used throughout Mastra, was written aserror: {}and the real failure was lost. The most visible symptom wasError listing tools for agentwith no details.PinoLoggernow applies Pino's standard error serializer to theerrorkey as well, so the type, message, and stack are recorded. The built-inerrkey keeps working. Values undererrorthat are not error-like (no stringmessageproperty) are passed through unchanged. Error-like plain objects are normalized to the same{ type, message, stack }shape with their own fields preserved.A new
serializersoption lets you override or extend the defaults:new PinoLogger({ serializers: { error: err => ({ message: err.message }) }, });
@mastra/mcp@1.17.3
Patch Changes
-
Fixed MCP tools not validating structured tool results against the tool's output schema. Tools rebuilt from a cached catalog with toolFromDefinition / toolsFromDefinitions (and live-discovered tools whose result bypasses the SDK check) now validate structuredContent before it reaches the model, and return the same structured validation error that createTool produces on mismatch. Valid results, in-band tool errors, and results without structuredContent are unchanged. Fixes #22549 (#22779)
-
Required @mastra/core 1.64 or newer so MCP can use the tool output validation API added in that release. (#22817)
@mastra/memory@1.28.2
Patch Changes
-
Added persistent reminder conversations and asynchronous
ask_memoryquestions with correlated partial and terminal replies. The tool returns immediately with a reply ID and pending status, then delivers answers later as correlated signals. (#22783)Enable the experimental reminder sidekick on observational memory:
import { Memory, Subconscious } from '@mastra/memory'; const memory = new Memory({ options: { observationalMemory: { model: 'openai/gpt-5-mini', experimental_subconscious: new Subconscious({ observation: ['remind'] }), }, }, });
-
Improve tool schema compatibility with providers that validate tool definitions server-side. (#22487)
-
Fixed observational memory prompts appearing in stored conversation history. (#22324)
@mastra/observability@1.17.5
Patch Changes
-
Fixed a startup crash on older
@mastra/coreversions by defining two small id helpers locally instead of importing them from core. (#22889)This package imported
generateSignalIdandresolveExportedSpanIdfrom@mastra/core/observability. Both are recent additions to core —generateSignalIdin 1.26.0,resolveExportedSpanIdin 1.63.0 — while the declared peer range still accepted@mastra/corefrom 1.16.0 up. A named ESM import of an export that does not exist fails when Node links the module graph, so an older core installed with no warning and then took the whole app down before any application code ran:SyntaxError: The requested module '@mastra/core/observability' does not provide an export named 'resolveExportedSpanId'Most projects never named this package — it arrives as a transitive dependency of an observability exporter such as
@mastra/langfuseor@mastra/otel-exporter— so the failure typically surfaced first in a deploy.Both helpers are self-contained:
generateSignalIdwrapscrypto.randomUUID, andresolveExportedSpanIdis structurally typed against an optional span method rather than any core class. Keeping local copies removes the version coupling entirely and makes the declared>=1.16.0range true again, rather than moving the floor up to 1.63.0.No API change. If you hit the error above, this release fixes it without requiring a
@mastra/coreupgrade.
@mastra/pg@1.22.3
Patch Changes
- Fixed PgVector failing with "Vector table does not exist" when no schemaName is configured and the connecting role has a same-named schema on its search_path. Catalog lookups used by listIndexes, describeIndex and the namespace migration now resolve through the effective search_path (like the table creation already did) instead of assuming the public schema. Without an explicit schemaName, listIndexes now reports vector tables from every schema on the search_path. Fixes #22545 (#22827)
@mastra/platform-workspace@1.5.0
Minor Changes
-
Added reusable sandbox templates to Platform workspaces. Build templates through
PlatformSandboxwith the portableTemplate()API; Platform content-addresses each serialized definition for reuse. Public repositories can be warmed lazily withcreateRepoTemplate(). UsecpuCount()andmemoryMB()to size E2B template builds and sandboxes created from the exact or a resource-matched stale build;createRepoTemplate()accepts the same sizing as plain options. Railway ignores these resource methods. (#22065)const sandbox = new PlatformSandbox({ environmentId, template: Template().cpuCount(4).memoryMB(8192).runCmd('pnpm install'), }); // createRepoTemplate takes the whole sandbox context: a session with no // repository gets undefined back and boots the provider default. const repoSandbox = new PlatformSandbox({ environmentId, template: createRepoTemplate({ getRepositoryAccess: async () => ({ cloneUrl: 'https://github.com/mastra-ai/mastra.git' }), setupCommand: 'pnpm install --frozen-lockfile', memoryMB: 2048, }), });
Template environment values are serialized by default. Pass
{ ephemeral: true }tosetEnvs()for short-lived build credentials that must stay outside the definition, identity, persistent record, and runtime environment.Template.build()can eagerly start or reuse the provider build without provisioning a sandbox. Railway includes transient values in its provider cache input, so rotating one may trigger another Railway build while the Platform template ID remains stable.PlatformSandbox.start()never blocks on a template build. When the exact template is not yet ready, Platform boots the sandbox on the best available fallback (an E2B prior member of the same family with matching effective resources if one exists, otherwise the provider base template) and builds the exact template in the background. A provider-base fallback may use provider-default resources. The sandbox surfacestemplatePendingfor observability; reconcile filesystem state in your own runtime setup (for example, anonStarthook that runsgit fetch && git checkout <sha>).Template().withFamily(key)attaches a caller-supplied family key that groups successive builds of the "same thing" (e.g. the same repository+workdir across commits) so an E2B definition can warm-start on a resource-matched prior member of the same family. Railway doesn't use family fallback.createRepoTemplate()populates the key automatically asrepo:<cloneUrl>:<workdir>. -
Changed Platform sandboxes to use E2B by default. Set sandboxProvider or SANDBOX_PROVIDER to railway to opt into Railway. (#22065)
-
createRepoTemplateacceptsbuildEnv: environment variables for the build steps only (for example, remote cache credentials). They never enter the template definition or identity. Template fallback warnings now redact credentials. (#22698)
@mastra/playground-ui@52.0.0
Minor Changes
-
Render server-defined trace signals in catalog order with custom labels, colors, lifecycle progress, and built-in fallbacks. (#21758)
<TraceIntelligenceProvider signalCatalog={entity.signalCatalog}> <TraceIntelligenceEntityDetail entityType={entity.entityType} entityId={entity.entityId} /> </TraceIntelligenceProvider>
-
Added a Messages tab to trace details so developers can review the user message, response, and tool calls for an agent turn. (#22911)
-
Added a
shadow-paneltoken and a--chart-soft-1through--chart-soft-5sequential color ramp to the design system. (#22713)shadow-panel — the resting elevation for a panel that sits on the page rather than floating over it. It reads one step below
shadow-dialog, so a page tiled with panels still looks like a single plane.<div className="border-border1 bg-surface3 shadow-panel rounded-xl border">…</div>
--chart-soft-1..5 — one hue, lightness carrying the reading, for a single measure shown at five depths. Use it where
--chart-1..5does not fit: that palette is categorical (five series, no order between them), this one is ordered. It flips with the theme, darkening on white and brightening on near-black.<Bar fill="var(--chart-soft-1)" />
-
Removed the separate
Chip,ChipsGroup, andStatusBadgeexports.Badgeis now the single compact label and status primitive, with nine color-based variants, muted emphasis, sizes, icons, and dot or pulse indicators. Its variants areneutral,green,red,blue,yellow,purple,orange,cyan, andpink; omittingvariantusesneutral. (#22640)ChipsGrouphas no direct replacement. Use a layout element appropriate to the surrounding UI aroundBadgeinstances.Badgenow renders an inline<span>instead of a<div>, andBadgePropsnow extendsHTMLAttributes<HTMLSpanElement>instead ofHTMLAttributes<HTMLDivElement>. Update block-layout assumptions and div-specific refs or handlers when migrating.Badges use soft corners and a subtle ring, with an inner shadow in light mode and an inner glow in dark mode.
Before:
import { Chip, ChipsGroup } from '@mastra/playground-ui/components/Chip'; import { StatusBadge } from '@mastra/playground-ui/components/StatusBadge'; <ChipsGroup> <Chip color="purple" intensity="muted">Baseline</Chip> <Chip color="blue" intensity="muted">Candidate</Chip> </ChipsGroup> <StatusBadge variant="success" withDot>Connected</StatusBadge>
After:
import { Badge } from '@mastra/playground-ui/components/Badge'; <div className="flex items-center gap-1"> <Badge variant="purple" emphasis="muted">Baseline</Badge> <Badge variant="blue" emphasis="muted">Candidate</Badge> </div> <Badge variant="green" indicator="dot">Connected</Badge>
Patch Changes
-
Pinned the lucide-react peer dependency to the workspace catalog, so the published range tracks the version the design system is actually built against. Consumers now need lucide-react 1.37 or later. (#22718)
-
Fixed flat and factory section headings to use medium weight. (#22900)
-
Improved trace search in Studio: when a span matches your search only through its metadata, attributes or error payload, its name in the timeline is now painted in a distinct color so you can see why the row is there without opening it. Spans matching by name keep the usual highlight. (#22660)
-
Fixed span search results being hidden below the fold: opening a span from the traces search now scrolls the first highlighted match in the span detail panel into view (#22690)
-
useInViewaccepts an optionalrootref so infinite-scroll sentinels can observe a list's own scroll viewport instead of the window. The Studio/inboxpage now uses the sharedPageLayout,Tabs, andDataListcomponents with per-list scrolling and infinite loading for feedback. (#22805) -
Redesigned the trace side panel summary in Studio. The metadata grid was replaced with a compact, single-line description under the trace title using icons and tooltips for the linked entity, start time, duration, input and output tokens, and estimated cost. The "Details" tab is now labeled "Spans", and secondary trace header actions are consolidated into a single actions menu. (#22804)
-
Improved the Studio traces list: combined the Date and Time columns into a single Created column, capped the Input column width so other columns stay visible, rendered trace status as a colored badge, and made the list shrink to the viewport instead of scrolling horizontally. Renamed the trace panel action to "Add full trace to dataset". (#22682)
-
Simplify the Trace Intelligence signal settings pane and correct index controls and pending-signal elevation styling. (#22908)
@mastra/react@1.4.10
Patch Changes
- Moved the lucide-react icon dependency to 1.37, in step with the rest of the repo. No API change: the icons ship inside the built bundle and never appear in the published types. Apps pinned to lucide-react 0.x keep working, they just resolve a second copy. (#22718)
@mastra/s3@0.6.2
Patch Changes
- Fixed S3 file stats to report MIME types so workspace read_file can return supported media correctly. (#22683)
@mastra/server@1.64.0
Patch Changes
-
Fixed the browser viewer registry giving up permanently when no browser toolset was available on first connect. It now retries the lookup when the next viewer connects. Related to #22537 (#22826)
-
Serialized agents now report a
hasBrowsercapability flag that is true for agent-level SDK browsers and workspace-level CLI browsers (which expose no SDK tools). Fixes #22535 (#22789) -
Fixed the Studio browser viewer checking whether the wrong thread's browser was running. When a viewer connected for a specific thread, the server asked the browser toolset about the globally "current" thread instead of the viewer's thread, which could log "Browser ready" and "Browser not running" for the same thread and leave the viewer stuck waiting. The viewer's thread ID is now passed through so the check answers for the right thread. Fixes #22538 (#22815)
-
Fixed suspended tool responses timing out while the resumed agent run continues. The endpoint now acknowledges immediately, preventing spurious 504 responses and delayed response-body errors for long-running continuations. (#22680)
-
Added a startup warning when
server.authis configured withoutmapUserToResourceId. Without that callback, built-in routes trust the resource ID sent by the client (for examplememory.resource), so an authenticated user could read or write threads belonging to another user. ConfiguremapUserToResourceIdto derive the resource ID from the authenticated user. Fixes #22875. (#22915)
@mastra/upstash@1.4.4
Patch Changes
- Corrected the minimum supported @mastra/core version to match this store's runtime dependencies. (#22564)
Other updated packages
The following packages were updated with dependency changes only: