Update dependency @mastra/core to v1 - #12
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
2 times, most recently
from
April 18, 2026 08:52
6de8b46 to
b37e28c
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
4 times, most recently
from
May 2, 2026 01:49
89500b2 to
c6c04dd
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
2 times, most recently
from
May 12, 2026 09:49
0098570 to
19b0b67
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
6 times, most recently
from
May 23, 2026 00:33
8819cf7 to
ce69b78
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
7 times, most recently
from
June 2, 2026 05:51
1c3a41f to
f14940c
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
5 times, most recently
from
June 12, 2026 23:30
0d1eb5f to
00dbc1f
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
2 times, most recently
from
June 20, 2026 08:38
d53662f to
734056f
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
2 times, most recently
from
June 27, 2026 06:35
f8bb9dd to
9002d5d
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
2 times, most recently
from
July 4, 2026 02:10
9e70c7d to
2453e38
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
4 times, most recently
from
July 12, 2026 11:49
eb74635 to
6deb1bd
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
3 times, most recently
from
July 20, 2026 21:12
646a6c6 to
0c235d6
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
4 times, most recently
from
July 30, 2026 16:57
166e665 to
0e8ca18
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
3 times, most recently
from
August 8, 2026 00:57
dd69ca4 to
fc14cd5
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
3 times, most recently
from
August 14, 2026 22:57
debf13c to
3bd730d
Compare
renovate
Bot
force-pushed
the
renovate/mastra-core-1.x
branch
from
August 15, 2026 09:14
3bd730d to
bf87856
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
^0.8.0→^0.8.0 || ^1.0.00.8.3→1.58.0Release Notes
mastra-ai/mastra (@mastra/core)
v1.58.0Compare Source
Minor Changes
Add
resolveSessionandonStaleToolApprovalto agent controller channels. (#21094)resolveSessioncreates the session for a mapped channel thread in place of the built-in call. It runs before any session exists, so a host can refuse a request before a session, a model call, or any output happens, which is somethingonSessionStartcannot do, because it runs after the session is created and swallows errors. A refusal is silent: the chat thread gets nothing, so the host's authorization message never lands in a shared channel. Other failures still post an error to the thread as before, and a refusal is distinguishable asChannelSessionRejectedErrorwith the original error as itscause.Approval actions now resolve their session with the action's own request context, so a shared install can revalidate the person answering an approval instead of trusting the request that opened the session.
onStaleToolApprovalreports approval actions that have no matching parked gate, which is every approval answered after a restart. Mastra still refuses to run the tool; the hook lets a durable host settle that attempt rather than dropping the answer. It receives therunIdthe approval card was rendered for: the attempt the user answered, plus the session'scurrentRunId, which after a restart is usually null or a different run.Added typed experiment provenance and grouping fields that persist across synchronous and asynchronous runs and can be filtered when listing experiments. (#20645)
Added
instructions.tsas a code alternative toinstructions.mdfor file-based agents. Use it when the prompt needs TypeScript, for example when it's built from shared constants or resolved per request. (#20847)Before, a computed prompt had to move into
config.ts, splitting it away from the agent's other instructions:Now it lives in its own file, next to
config.ts:The file default-exports a string, a system message, or a function returning one.
agentInstructions()is an identity helper that only adds editor types.Precedence
A function
config.instructionsstill wins over both files, theninstructions.tswins overinstructions.md, which still wins over a staticconfig.instructions. Defining instructions in more than one place logs a warning naming both sources and which one wins.One upgrade case needs a rename. If an agent directory already holds an unrelated
instructions.ts, for example a helper thatconfig.tsimports, Mastra now reads that file as the agent's instructions instead of its old source, and the build fails if the file has no default export.Added AgentController live-session deletion with a process-local listener. Deletion is runtime-only: persisted threads and messages remain in storage and can be resumed by a future session. (#21174)
Add
beforeAll,afterAll,beforeEach, andafterEachlifecycle hooks torunExperimentfor setting up and tearing down test data around an experiment run.beforeAllfailures fail the experiment,beforeEachfailures mark the item failed and skip execution (withafterEachstill running), andafterEachfailures are logged as warnings. (#21082)Added an
openIfEmptyoption to streamed tool display results. Set it to (#20909)falsewhen a tool lifecycle chunk should update only an active streamingsession:
By default, stream results continue to open a session when needed. Static
channels continue to use plain-text fallback rendering.
Added support for schema-aware routes created with
createRoute()inserver.apiRoutes. (#21184)Added file-based schedules for agents (#20711)
File-based agents can now declare recurring tasks in a
schedules/directory next to their tools and skills. Mastra registers them into schedule storage at startup, so a scheduled agent no longer needs any runtime registration code.Each file is one schedule: a cron expression plus exactly one execution mode. Prompt mode runs the owning agent with a fixed message.
Handler mode computes the fire when it triggers, and returning
nullskips it.A schedule's id is its path under
schedules/with the extension stripped, sobilling/sweep.tsbecomesbilling/sweepand stays stable across builds. Editing a cron patches the stored schedule and recomputes its next fire time, deleting the file deletes the schedule, and pausing a schedule through the API survives a redeploy. Schedules created withmastra.schedules.create(...)are in a separate namespace and are never touched by this sync.A schedule can also be a Markdown file, using cron frontmatter with the document body as the prompt.
Declaring a schedule is enough to start the scheduler. Schedules are supported on root agents only; a
schedules/directory undersubagents/fails the build, because the scheduler cannot resolve a subagent as a run target.defineScheduleis exported from both@mastra/core/agentand@mastra/core/schedules, so authoring a file-based agent needs a single import path.Build and dev support the same convention: schedules are discovered at build time, Markdown schedules fail the build with a message naming the file when the cron is missing, the body is empty, the frontmatter has an unknown field, or the YAML is unparseable. That last case has its own message because a leading
*is a YAML alias, socron: */5 * * * *needs quoting. The dev server rebuilds when a Markdown schedule changes.Added a
command_exitsession event to the agent controller. Subscribers now receive the exit code and success flag of each foregroundexecute_commandtool call, alongside the existingshell_outputstream: (#21211)Previously the exit outcome was only visible inside the tool result text, so observers could stream a command's output but never tell whether it succeeded.
Made the workspace optional when creating an agent controller session. Previously
createSession()threwA session requires a valid workspace instanceunless a workspace was configured, which blocked chat-style sessions that only need threads, state, and agent runs. (#21084)Session.getWorkspace()now returnsWorkspace | undefined, so check the result before using it. Passing a value that is not aWorkspaceinstance is still rejected. Sessions that do configure a workspace are unchanged, including workspace initialization and theworkspace_ready/workspace_errorevents.Closes #20594
Renamed the beta stored workflows feature to dynamic workflows.
mastra.addStoredWorkflow()is nowmastra.addDynamicWorkflow(),addStoredWorkflows()is nowaddDynamicWorkflows(), theStoredWorkflow*types are nowDynamicWorkflow*, andworkflow.originreports'dynamic'instead of'stored'. (#20938)Added a reusable Workflow Builder authoring API for discovering registered primitives, validating complete workflow definitions, and creating strict-provider-safe builder agents. Built-in workspace tools now expose explicit output schemas so workflow authors can infer tool compatibility. (#21210)
Added a
requestContextKeysoption to scorer runs that controls which request-context values are recorded on the eval's span input for repeatability. (#20808)Previously the entire request context was recorded on every scorer-run span. Because request context is an arbitrary, app-controlled bag, that could persist secrets or PII stored under any key into exported traces and datasets. Scorer runs now record nothing from the request context by default — you opt in per key.
What changed
requestContextKeys): nothing from the request context is recorded.['*']: the whole context is recorded (the framework-managed auth token stays redacted).This is separate from the observability config's
requestContextKeys, which controls live span metadata. Recording a run so it can be reproduced later and surfacing keys on every live span are different concerns, so they are controlled independently.Example
Added a delegated request context to
onDelegationStart. Each subagent run receives a context map derived from its parent, so hooks can add values before dynamic agent configuration resolves without changing the parent context. (#20853)Subagent request contexts inherit caller entries but exclude parent memory, thread, and resource identity. Setting or deleting entries during a subagent run no longer changes the parent context map or another concurrent delegation's map.
Added an opt-in
toolCallConcurrencystrategy that parallelizes safe tool calls when an approval or suspending tool is registered but not actually called in a step. (#21106)Previously, registering any tool that requires approval or can suspend forced every tool-call batch to run one at a time, even when the model never called that tool. You can now opt in to resolving concurrency from the tools the model actually called:
Before
After
The default strategy ('available') keeps the existing conservative behavior. This works across both the standard loop and the durable engine. Closes #20100.
Added tracing to dynamic agent skills resolvers. The resolver now runs inside a
resolve-skillsspan, so skills fetched from an external service show up in the agent's trace instead of disappearing, and it receivestracingContextfor creating child spans of its own — the same pattern tools already use. (#20949)On metadata reads such as
agent.listSkills()no agent is running, sotracingContext.currentSpanisundefined— guard span usage with?.as shown above.Fixed agent streams closing silently when a provider ends the stream with
finishReason: 'error'but sends no error payload (for example, Google models reportingMALFORMED_FUNCTION_CALL). Previously the stream closed with no error part andonErrornever fired, so a failed run looked identical to a turn that produced no text. The stream now emits anerrorchunk and callsonError, and error processors can intercept and retry the failure. (#20302)Added
stepResult.rawReasontostep-finishandfinishchunks. It preserves the provider's own finish reason instead of collapsing it to'error', so you can tell distinct provider failures apart:These runs previously resolved as if they had succeeded with empty output. They now fail the same way a provider-reported error already did:
agent.generate()rejects, and so do awaited stream promises such asstream.text. IteratingfullStreamstill completes normally, with anerrorchunk included.Add
includeResolvedToolstoToolSearchProcessor, making per-request tools (MCP tools that need the caller's credentials, or anything returned by a dynamictoolsfunction) searchable and withholding them from the prompt until the agent loads them. Previously only tools listed at construction could be searched, so dynamically resolved tools were always sent in full. (#21016)Added an explicit A2A Protocol v1.0 SDK export while preserving the existing v0.3 export. (#20811)
Set
tools.writeLockTimeoutMswhen a remote or cold-starting filesystem needs more than 30 seconds to accept a write. The write tool waits for the configured timeout before returning awrite-lock timeouterror. (#20809)The default is unchanged at 30 000 ms.
Channel agent replies now post as markdown by default, so Slack renders bold text, links, and tables natively and other chat platforms convert the reply to their own format. Previously the final reply was posted as literal plain text, which made standard markdown show up as raw
**bold**and[title](url)characters in Slack while the same reply rendered correctly in Studio. (#20971)This is a behavior change for every channel agent. If your agent was prompted to emit a platform dialect such as Slack mrkdwn to work around the old behavior, either remove those prompt instructions (recommended) or set the new
textFormat: 'plain'option on the channel adapter config to keep posting literal plain text:textFormatapplies to final reply text only. Tool cards, error messages, tripwire notices, and native streaming (which was already markdown) are unchanged. Postable channel messages now also accept a{ markdown: string }object alongside strings and card elements.Lightweight trace lists now work on every storage backend. Their rows carry an
inputPreviewso a list can render its preview column without transferring the whole prompt, plus a computedstatusand the spanmetadataso Studio's configurable trace columns work unchanged on the lightweight list. (#20677)ObservabilityStorage.listTracesLight()previously threw on any backend that did not implement it — which was every backend except ClickHouse, DuckDB and the in-memory store. It now defaults tolistTraces()with each row projected down, so all backends serve the same response shape. Backends that can push the projection into the query should still override it; that is what keeps the blob columns off the read path.lightSpanRecordSchemagains optionalinputPreview,statusandmetadatafields, andbuildInputPreview()/toLightSpanRecord()are exported for stores that derive the preview at read time.listTracesLightResponseSchemaalso gained thedeltaanddeltaCursorfields already present onlistTracesResponseSchema, so lightweight lists can be live-tailed.Note that
paginationonListTracesLightResponseis now optional, because delta-mode responses return a cursor instead of a page. Code that reads it directly needs a guard:Added
WorkspaceSandbox.snapshot()for persisting sandbox state when supported. (#21221)Added an optional
reasonwhen declining a tool call, so the model and your UI can see why a tool call was rejected instead of always showing "Tool call was not approved by the user". (#21085)The reason is retained with the tool call, so it is still there when the conversation is recalled later. It is supported by
declineToolCall,declineToolCallGenerateanddeclineNetworkToolCall, on both regular and durable agents. Omittingreasonkeeps the previous default message.Closes #20495
Added an
onDetectioncallback toPIIDetectorandPromptInjectionDetectorso you can observe detection results and build your own metrics. (#21123)The callback receives the raw detection result, the analyzed input, whether it crossed the threshold, and which strategy was applied.
Errors thrown from the callback are logged and never interrupt processing. Closes #13336
Patch Changes
dependencies updates: (#19783)
posthog-node@^5.46.1↗︎ (from^5.37.0, independencies)Stop AgentController sessions from re-sending the whole conversation state on every streamed chunk. (#21095)
A session emits one
message_updateper streamed delta, and the session bus fanned out a fulldisplay_state_changedsnapshot alongside each one. Every snapshot carried the growing message pluseach finished tool's arguments and result, so a long turn with a large tool result re-sent that result
thousands of times. A turn with 500 deltas and a 100 KB tool result put roughly 50 MB of snapshots on
the wire; subscribers holding the event log could exhaust memory.
Snapshots for high-frequency events are now coalesced, so a burst of deltas produces one snapshot per
frame instead of one per delta. A snapshot always describes the complete current state, so no
information is lost: any dropped intermediate snapshot is immediately superseded, and a pending
snapshot is flushed before the next non-coalesced event so ordering and final state are unchanged.
The engine also skips its per-delta message clone when a session has no subscribers.
Event types, payload shapes, and delivery order are unchanged.
Fixed
AgentController.resolveWorkspacehanding one session's workspace to every session created after it. On a controller configured with a dynamic workspace factory, the first call cached its result over the factory itself, so later sessions skipped resolution and ran against the first session's workspace instead of their own. (#21144)resolveWorkspacenow returns the workspace a session already resolved at creation, and caches nothing on the controller. Two smaller fixes come with it:isWorkspaceReady()no longer flips tofalsefor factory configs, and slash commands read the same workspace instance the session's runs use.Update provider registry and model documentation with latest models and providers (
45a9147)Fixed thread title generation being dropped on serverless runtimes by accepting an optional
serverless.waitUntilongenerate()/stream()so title persistence stays alive after the response without blocking the run. (#20682) (#20996)Made the workspace LSP manager's per-file lock hand out access in arrival order. Diagnostics requests for the same file were already serialized; a request that arrived at the moment the previous one finished could jump ahead of requests that had been waiting longer. Requests for different files still run in parallel. (#21101)
Fixed deferred notifications accumulating dead workflow records forever. The internal dispatcher runs on a schedule (every minute by default) and left a completed snapshot row behind on every run, so
mastra_workflow_snapshotgrew unboundedly — tens of thousands of rows that were never read again. These runs no longer persist snapshots. Fixes #20254 (#20970)Add a workflow
onStartlifecycle hook. It is awaited before a run executes, receives the run context, and fires only on initial start — not on resume, restart, or time travel. UnlikeonFinish/onError, errors thrown inonStartreject thestart()/stream()call so it can act as a pre-flight gate, for example a quota check. (#21063)Add
bundler.minifyto minifymastra buildoutput (#21032)mastra buildalways emitted unminified code, which is larger than necessary when packaging for production — a container image or an on-prem deployment.Set
bundler.minify: trueto minify the emitted bundle. Minification runs over whole chunks, so comments and whitespace are dropped and local identifiers are shortened while exported names are preserved.Defaults to
false, so existing builds are unchanged.mastra devis never minified.Fixed dynamic workflows so object-form mapping configs keep working. Passing
mapConfigas an object toaddDynamicWorkflowpreviously failed at run time with"[object Object]" is not valid JSON; it now stays intact when the workflow is registered, saved, and loaded. (#21287)Allow the browser
viewportto be set to'window'so the page matches the real browser window instead of a fixed size. AddsresolveViewportSizeandresolveLaunchViewporthelpers plus aDEFAULT_BROWSER_VIEWPORTconstant for providers to resolve the setting consistently. (#21010)Prevent
streamLegacy()cleanup from hanging when an observer stream has queued events that have not been consumed. (#19921)Fixed
Mastra.shutdown()leaving database connections open when storage is aMastraCompositeStore. The composite had noclose()of its own, so shutdown silently skipped storage cleanup and any composed adapter (Redis, LibSQL, Postgres, ...) kept its client connected — leaving processes that wait for a graceful drain, such as test runners and Kubernetes pods handling SIGTERM, hanging until they were killed. (#20629)A composite now closes everything it was built from: the
defaultandeditorstores, plus any domain that owns its own connection. Each store is closed once even when it backs several domains, and a store that fails to close is logged and skipped so the remaining handles are still released. See #20621.Fixed Azure OpenAI routing to reject empty deployment names. (#21105)
Fixed
Mastra.startWorkers()so it no longer reads the schedules store on boot when the scheduler cannot start. Boot now skips that read if you setscheduler: { enabled: false }orworkers: false. Storage adapters that need request or tenant context no longer warn on every boot. Automatic detection of persisted agent schedules and deferred notifications is unchanged when you do not opt out. (#20982)Fixed the response cache serving one image's answer for a different image.
ResponseCachederives its key from the resolved prompt, but URL-valued image and file parts were serialized as{}, so two requests that differed only in which image they pointed at collided on the same cache entry. URLs now contribute their full href, and inline binary data contributes a digest of its bytes instead of being expanded one property per byte (which turned a 1 MiB image into ~11 MiB of intermediate JSON, hashed synchronously before every model call). (#20656)Fixed durable agent completion on remote workers so processed messages persist, thread titles generate, and prior turns can be recalled. (#20926)
Fixed sub-agent delegation failing when an LLM sends
maxStepsas a numeric string (e.g."10"instead of10). Delegation now accepts valid numeric strings and continues to reject invalid values such as non-integers or numbers below 3. (#20793)Fixed
includeinlistMessagesandlistMessagesByResourceIdso it can no longer return a message that belongs to a different resource. When you pass aresourceId, the target message and its surrounding context messages now stay inside that resource. Includes that cross threads inside the same resource keep working, so semantic recall withscope: 'resource'is unchanged. (#20984)Behaviour change in the in-memory store
The in-memory store read the context window from the thread you queried. It now reads the window from the thread that owns the target message, which is what the SQL stores already did. This only changes the result when an
includeentry names a message from another thread.The in-memory store also ignored
includeinlistMessagesByResourceId. It now returns the included messages, like@mastra/libsqland@mastra/pgdo.Fixes #20604.
Added a
firstMeaningfulExecAttimestamp to source-control sessions, recording when the session's agent completed its first successful sandbox command. Together withfirstMessageAtthis measures time-to-first-meaningful-exec: how long a user waits between sending their first message and the agent actually doing work in a live sandbox. The value is written once per session and is available on all session read APIs; setup commands run by the platform itself (skill loading, repo checkout) do not count. (#21211)Fixed agent schedules targeting stored agents being permanently deleted after a server restart. Both deletion paths are covered: the scheduler tick loop no longer counts an unhydrated stored agent as a missing target (it confirms absence against the editor before reclaiming the schedule row), and the fire path resolves stored agents through the editor before self-cleaning. Schedules are never deleted when the editor lookup fails transiently — only a confirmed miss from both the registry and the editor reclaims the row. (#19791)
Fix
deepEqualreturningtruefor values of mismatched shapes. ADatecompared against a plain object (e.g.deepEqual(new Date(), {})) fell through to the generic object-key comparison — and since aDatehas no own enumerable keys, it matched{}. Likewise an array compared against an object with matching index keys (e.g.deepEqual([1, 2], { '0': 1, '1': 2 })) returnedtrue. Added guards so an array only equals an array and aDateonly equals aDate; the checks apply recursively to nested values. (#21146)Improved A2A v0.3 remote task continuation. A2AAgent now resumes input and authentication requests using the original task ID and surfaces protocol errors returned by remote agents. (#20708)
Fixed DurableAgent terminal cleanup so it also clears
workflow.events.v2.<runId>, preventing orphaned no-TTL counter keys on persistent caches (#20786). (#20961)Fixed durable agent streams crashing when consumed by
@mastra/ai-sdkand other chunk converters. Thestep-startstream chunks now use the canonical shape, matching the regular engine and preventing destructuring errors when reading the chunk payload. (#19575)Fixed Workspace search indexing sending one embedding request per document. (#21067)
A batch-capable embedder (one branded with
batch: true) was only used when the search engine ran in lazy mode, whichWorkspacenever enables. Indexing a directory therefore cost one embedding round trip per file no matter what the embedder supported — indexing 500 files made 500 requests.indexManynow groups documents into batched embedder calls whenever the configured embedder is batch-capable, so those 500 files take 2 requests withmaxBatchSize: 256.Vector writes are bounded as well: a single
upsertnow carries at mostmin(maxBatchSize, 100)vectors instead of the whole batch, since each document's metadata carries its full text and several vector stores reject oversized write requests. Lazy-mode rebuilds that previously issued one largeupsertper flush now issue several bounded ones.An embedder declaring an unusable
maxBatchSize(0, negative, orNaN) now falls back to the default batch size instead of hanging or silently indexing nothing.Enqueue a
tool-output-deniedchunk when arequireApprovaltool is declined so live AI SDK clients resolve the pending tool call instead of hanging. Persistence asoutput-deniedalready worked; only the stream path was missing. (#20886)Fixed dataset experiment runs failing with a missing-thread memory error when the target agent has memory configured and the request context provides only a resource id (for example from auth middleware or Studio). Each dataset item now runs in its own fresh memory thread; explicitly supplied thread ids are still respected. Fixes #20663 (#20844)
Fixed nested agent-as-tool approvals so users see the inner tool and arguments while resumes retain the parent delegation identity (#20934). (#20948)
Fix
tryStreamWithJsonFallbacktreating a valid falsy structured-output value as undefined. The first-attempt check used!object, so a schema resolving to a falsy-but-defined value (e.g.z.boolean()->false,z.number()->0) was wrongly rejected and triggered an unnecessary JSON-prompt fallback stream. It now checksobject === undefined, matching the generate path and the stream fallback path. (#20628)Fixed an issue where observer cleanup failures no longer prevent legacy workflow streams from completing cleanly. (#20652)
Fixed workflow
.map()step arrays so they preserve branch results of{},0,false, and empty strings instead of returningnull. (#20896)Fixed a crash where updating a thread without a title (for example during observational memory buffering) could write a null title and violate the database's not-null constraint when running a newer @mastra/memory against an older storage package. Memory now checks whether the connected storage adapter supports partial thread updates and backfills the existing title for older adapters, so mixed-version deployments keep working. See #21041 for the original title-clobbering fix this makes backward compatible. (#21257)
Fixed durable agents losing custom model-facing tool output between workflow steps. (#20176)
Hardened
runEvalsthreshold checks: non-finite scores (for exampleNaN) now failmin/maxrange thresholds instead of passing, and invalid threshold shapes passed from JavaScript (strings,null, arrays) are rejected with a clearINVALID_SCORER_THRESHOLDerror instead of silently passing every score. (#20145)Fixed concurrent workflow tool approvals so each suspended call resumes the correct workflow run. (#20347)
Storage adapters now declare support for partial thread updates, letting newer @mastra/memory preserve existing thread titles instead of overwriting them, while remaining safe against older versions. (#21257)
Fixed experiment runs reporting a failed outcome instead of cancelled when cancellation interrupted an in-flight item. Cancelled experiment runs now consistently finish with a cancelled outcome, so standalone experiment workers exit with the cancellation exit code instead of a failure code. (#20719)
Fixed an active goal being reported as cancelled when its objective was written while a run was already in flight. The objective a goal state projection sees is now read from storage whenever the run-start read found nothing, so a goal started or restarted mid-run is no longer projected as having no objective. (#21255)
Fixed subscribed agent-controller runs so dynamic workspaces use the identity from the request that started the run. (#20658)
Fixed sendStreamResume() to resume suspended agent runs from storage after a server restart or when requests reach another instance. (#20602)
Fixed an agent reply loop on the iMessage channel. iPhone read receipts arrive as inbound messages with no text and no attachments, and each agent reply triggered another receipt. Channel messages with neither text nor attachments no longer start an agent run. Custom channel handlers still receive them. (#21240)
Fixed
session.abort()when a tool call is waiting on approval or parked in a suspension. (#20972)Aborting from a
tool_approval_requiredsubscriber raised an error and ended the run with reasonerror. It now completes with reasonaborted, and the gated call settles asoutput-deniedinstead of rendering as still in flight.Aborting while tool suspensions were parked (
ask_user,request_access) dropped them silently, leaving prompts on screen whose answers could never be delivered. Each dropped suspension now emitstool_suspension_cancelled. Fixes #20592Multi-step model generations now retain provider metadata from every completed step. (#19921)
Fixed a hang when two streams were started for the same workflow run at once. Resuming or time-traveling a suspended run twice concurrently (a double-clicked approval, a client retry, or two open tabs) left one of the two streams open forever, so the matching resume-stream or time-travel-stream HTTP request never ended. Each stream now closes itself independently. (#21126)
Agent scorers now run on the Inngest durable engine. (#21038)
An agent configured with
scorersnever had them executed when running viacreateInngestAgent()— no scorer ran, no spans, no persisted scores, and no error. Core's durable workflow gained anexecute-scorersstep that the Inngest workflow builder, a copy of it, never picked up.Scorer execution now lives in the durable workflow's shared module and is used by both engines, so scorers behave identically on either one.
Fixed output processors not being able to clear the final agent text. An output processor that redacts all assistant text to an empty string now correctly results in an empty
result.textfromgenerate()andstream(), instead of falling back to the original unprocessed model output. Fixes #19240 (#20998)Fix durable agents dropping
requestContextwhen a step is rehydrated on another process (for example an Inngest worker delegating to a subagent). Tool, memory, and workspace resolution now fall back to the run-level request context when the step input carries no request-context snapshot, so request-scoped configuration reaches subagents instead of resolving with an empty context. (#21015)Stamp the run's traceId into persisted assistant message metadata so a stored message can be correlated back to its trace. (#20928)
Previously a caller holding only a
messageIdhad no supported way to find the trace that produced it: message rows carry notraceIdcolumn and span records carry nomessageId. The traceId now rides along in the metadata that already carriedmodelIdandprovider, on both the regular and the durable agent path.This is forward-looking — messages persisted before this change have no traceId.
Fixed deferred notification deliveries failing with "No model selected" when the woken thread had no request context. The notification dispatch workflow re-sends deferred and summarized notifications long after the originating send, so any stream options attached to the original signal are gone; waking an idle thread then had no way to resolve a model. The notification delivery policy now drives the fix:
NotificationDeliveryDecisionacceptsstreamOptions, and the dispatcher re-runs the agent's delivery policy at delivery time (via the newagent.resolveNotificationDeliveryDecision()) to attach freshly resolved stream options to both individual and summary deliveries. OnlystreamOptionsis honored at dispatch time; the record's persisted schedule still governs when and how it is delivered. Receipt-time sends also honor the policy'sstreamOptionsnow: an immediate deliver or summarize-now wake attaches them too, with caller-supplied stream options taking precedence. Mastra Code wires its session-based stream options resolver through the Code Agent'sdeliveryPolicy.decide, layered on the default decision logic. This fix applies to threads whose session is live in the current process; deliveries with no resolvable session fall back to a bare wake, and the "No model selected" error now distinguishes the case where a run started without any controller session context. This re-lands the capability removed by the #18637 revert in the policy-driven shape that revert called for, and the@mastra/github-signalsbump only widens itsgetNotificationStreamOptionscallback return type to allowundefined. (#21113)Fix DurableAgent inference crashes and error reporting (#21138): (#21224)
onError.Let
onDelegationCompletecorrect a delegation result within the current run (#21042)A subagent that stops on a tool-calls step returns empty text, which the parent model
reads as a successful but empty delegation and narrates around ("I'll report back once
it returns"). The
feedbackreturned fromonDelegationCompleteis persisted to theparent's memory, so it only reaches the model on the next turn — after the parent has
already answered.
The hook can now return
resultText, which replaces the tool result text the parentmodel sees for that delegation in the run that is still executing.
Added an
onSessionStarthook toAgentControllerChannelsconfig, called once per session after it is bound to its mapped chat thread and before the first message dispatches. Messages arriving while the hook is still running wait for it instead of dispatching on an unconfigured session. (#20832)A host can already name a channel session through
resolveResourceId, but it never receives theSessionobject, which is created inside the channel machinery. Without a seam there, a host could only configure sessions it created itself, and channel-created sessions silently ran on the built-in default models. Hook errors are logged and swallowed so a session that cannot be configured still answers the message.Make
abort()stop durable agent runs that are executing in another process (#21009)A durable agent's steps often run somewhere other than the process that started them — another replica behind a load balancer, or an Inngest step worker.
abort()only flipped an in-memoryAbortController, which those processes never see, so aborting a durable or Inngest agent run silently did nothing in exactly the deployments durable agents exist for.Abort intent now travels over pubsub. The executing process picks the request up and flips its own controller, so the run unwinds the same way an in-process abort does and still emits its terminal stream event — consumers waiting on the stream are released instead of hanging.
abort()now returns a promise so callers can await dispatch; ignoring it preserves the previous fire-and-forget behavior.Fixed suspended runs that could fail to save after repeated tool calls. (#21002)
A run's snapshot no longer grows with every step it took before suspending, which keeps agents that make many tool calls before their first approval prompt under MongoDB's 16 MB per-document limit — past it, the snapshot was never written and the resume reported the run as missing. Runs suspended by earlier versions still load.
Fixed background tool calls so the model sees the completed result instead of the dispatch placeholder. (#21001)
An agent that dispatched a tool to the background kept reading "Background task started..." on every later turn, so it would re-run the tool or answer without the result. Unrelated provider metadata on the tool call is now preserved when the completed result arrives.
Fixed AgentController losing the second auto-approved tool result when sequential tool calls resume from a stale suspended snapshot (#19814) (#19940)
Fixed
convertFullStreamChunkToUIMessageStreamfrom@mastra/core/streamdropping the finish reason. The terminalfinishchunk now carriesfinishReason, so a UI message stream built on this export can tellstop,length,content-filter,tool-callsandotherapart. Fixes #20562. (#20983)Fixed assistant message history so provider-executed tool failures are preserved instead of remaining as pending calls. Matching tool invocations now use
state: "output-error", and the normalized provider message is stored inerrorTextwith a fallback when no usable message is available. Fixes #20715 (#20716)Resolve dynamic models once when preparing assigned tools. (#21281)
Fixed input processors receiving an undefined agent in their context when a durable agent run was resumed by a signal or schedule. The running agent is now passed through the processor workflow, so processors that rely on it (such as working memory and semantic recall) work correctly on wake. (#21102)
Fixed parallel sub-agent approvals and suspensions so every persisted target remains resumable after refresh. (#20700)
Fixed failed workspace commands to label standard output and standard error. (#20774)
Fixed
result.objectbeing stale after an output processor rejected a structured-output attempt withabort(reason, { retry: true }). The retried attempt object is now returned, matchingresult.text, instead of the rejected attempt object. Fixes #20570 (#20999)Fixed RegexFilterProcessor redact strategy to redact matches split across stream chunks, and added a
streamCarryoverSizeoption for custom rules whose matches can be longer than the default 128-char window. Fixes #21049 (#21050)runEvalsnow acceptsgatestogether with a categorized scorer config (AgentScorerConfig/WorkflowScorerConfig) without a TypeScript error. Previously a call likerunEvals({ target, data, gates, scorers: { trajectory: [...] } })failed to compile with TS2769 because the categorized-config overloads didn't declaregates, even though the runtime already ran gates independently of the scorer shape. The optionalgatesproperty was added to both the agent and workflow categorized-config overloads. (#21143)Fixed model configuration validation to safely reject null values. (#21192)
Fixed AgentController session preferences (thinking level, notifications) reverting to defaults after a server restart. These preferences now survive restarts and follow the conversation: reopening a thread restores the values that were active in it, including on self-hosted Factory deployments. ([#̴
Configuration
📅 Schedule: (in timezone America/Los_Angeles)
* * * * 1-5)🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about these updates again.
This PR was generated by Mend Renovate. View the repository job log.