fix(deps): update dependency @mastra/core to v1#48
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
7b23759 to
4ca1f39
Compare
c64fbb8 to
c33d6c8
Compare
6ad1902 to
ef06b25
Compare
181489a to
7f2bbe9
Compare
9583e0f to
bf7edb0
Compare
ee1ce1f to
877ff2d
Compare
0eeb3ee to
aad6296
Compare
be8d060 to
3342730
Compare
7283845 to
351503f
Compare
90f71f3 to
a7d4d63
Compare
60ada13 to
95f67b1
Compare
946963a to
1ba24e1
Compare
aac0766 to
eb03fc4
Compare
5e11def to
85450c8
Compare
de611bf to
604431b
Compare
604431b to
81b87c4
Compare
81b87c4 to
058fb31
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.12.1→^1.0.0Release Notes
mastra-ai/mastra (@mastra/core)
v1.49.0Compare Source
Minor Changes
Added opt-in storage retention. Declare per-table
maxAgepolicies in theretentionconfig, then callstorage.prune()to delete rows older than their age. Anything you don't configure is kept forever, so there is no change until you opt in. (#18733)Retention covers growth tables across ten domains —
memory(threads, messages, resources),threadState,observability(spans),scores,workflows(run snapshots),backgroundTasks,experiments,notifications,harness(sessions), andschedules(fire history). Anchors are chosen somaxAgeis honest: creation time for append-only logs, last activity for workflow snapshots and thread state, and completion time for background tasks and experiments (in-flight work is never pruned). User-authored artifacts and config (agents, skills, workspaces, datasets, schedule definitions, and so on) are not prunable.prune()is safe on large tables: it deletes in bounded, batched, resumable, cancellable chunks and never locks the database for long. Call it from your own scheduler; when a result reportsdone: false, eligible rows remain and the next run continues.prune()only deletes rows — reclaiming disk to the OS is left to the underlying database and the operator.Added maxDurationMs, maxWidth, and maxHeight options to BrowserRecordingOptions. These can now be set on the recording config object to provide defaults for every recording, instead of relying on agent instructions to pass them to the tool at start time. (#18814)
Per-recording overrides via the browser_record tool still take precedence.
File-based agents can now nest subagents up to three levels deep. A subagent directory can declare its own
subagents/, and each level is assembled and wired into its parent as a delegation tool. Levels deeper than the cap are ignored with a warning. (#18780)Fixed a cross-tenant data-access issue on datasets by scoping
DatasetsManager.getandDatasetsManager.deleteto tenancy filters. (#18750)Previously
get({ id })anddelete({ id })looked up a dataset by its primary key alone. Any caller who knew a dataset id could read or delete it regardless of whichorganizationId/projectIdit belonged to. This is now closed at the storage layer via a scoped SQL predicate (option (a) — no fetch-then-assert).What changed
DatasetsManager.getandDatasetsManager.deleteaccept optionalorganizationIdandprojectId.Datasethandle and forwarded to every downstream storage call (getDetails,update,addItem, item batch ops,startExperimentAsync).getDatasetById,deleteDataset) gained an optionalfilters?: DatasetTenancyFiltersarg.AddDatasetItemInput,UpdateDatasetItemInput,BatchInsertItemsInput,BatchDeleteItemsInput) andUpdateDatasetInputaccept optionalfiltersfor the internal existence check.Behavior
getthrows NOT_FOUND (returns null at the storage layer) anddeleteis a silent no-op — matching how a missing id already behaves, so existence does not leak through error timing or messages.Example
Added
scoreTrace()andscoreTraceBatch()to@mastra/core/evals/scoreTracesfor scoring stored traces without re-running the agent. (#18331)scoreTrace()can score either a stored trace reference or a preloadedTraceRecord, and it returns the persistedScoreRowDataafter the write.scoreTraceBatch()runs one scorer instance across multiple stored traces with bounded concurrency and returns per-target success and failure results.Why
This gives baseline-style callers a small public API for persisted trace scoring when they already have a scorer instance, without widening the existing workflow-based
scoreTraces()API.Before
After
Add optional
batchId,datasetId, anddatasetItemIdfields to persisted scores so saved baseline scores can be grouped as one scoring pass and joined back to the dataset items they came from. (#18331)scoreTrace()accepts top-levelbatchId,datasetId, anddatasetItemIdwhen persisting a score for a stored trace.ScoreRowDataand score save payloads now include nullablebatchId,datasetId, anddatasetItemId.Added multi-tenant scoping to stored scorer definitions. Stored scorers now persist optional
organizationIdandprojectIdon the definition record, andlist/listResolvedaccept matching filters to scope results by tenant. The Postgres adapter backfills the new columns and applies the scoped filters; tenancy lives on the record while version snapshots stay pure config. (#18331)Added optional
organizationIdandprojectIdfields to scores for multi-tenant isolation. Scores can now be saved with tenancy metadata and thelistScoresBy*methods accept afiltersoption to scope results by organization and project. (#18331)projectIdidentifies the project scope, separate fromresourceIdwhich continues to mean the agent memory resource.Agents using models that dropped support for
temperature,topP, ortopK(such asclaude-opus-4-7orgpt-5-pro) no longer crash with a 400 error. The model router now automatically strips unsupported sampling parameters before the request is sent — no configuration or processors needed. (#18622)Patch Changes
Fixed signal drain parity for durable agents. Signals sent to a running durable agent (via sendSignal or sendMessage) are now consumed and echoed to the client stream, matching the behavior of regular agents. This includes initial signal echoes on the first model request, pre-run signal drain before the first LLM call, within-iteration signal drain between tool execution and task completion, and inter-iteration signal drain in the loop predicate that forces continuation so the LLM sees newly arrived signals. (#18732)
Update provider registry and model documentation with latest models and providers (
0f69865)Surface persistence failures in experiment runs. Previously, when
addExperimentResultthrew duringrunExperiment, the failure was silently logged withconsole.warnand the run continued. The item was still counted as succeeded or failed based on the agent run outcome, soExperimentSummary.succeededCountcould report more rows than actually existed inmastra_experiment_results— silent data loss with no signal to the caller. (#18716)Now each item result carries an optional
persistenceError: { message } | nullfield, and the summary exposes an optionalpersistenceFailures: numbercounter. The raw error (including stack) is logged internally via the Mastra logger and intentionally omitted from the returned object so the summary can safely cross trust boundaries (e.g. UIs, API responses) without leaking internal paths. Target-run counters (succeededCount/failedCount) still reflect what the target did, and callers can inspectpersistenceFailuresto detect when the DB is out of sync with the returned summary and decide whether to retry or alert. The persistence failure is also logged via the Mastra logger at error level instead ofconsole.warn.Both fields are optional on the types so external mocks / wrappers don't need to hand-construct them; the runner always populates them (
null/0on the happy path).Fixed durable agent parity gaps: emit
startchunk for correct stream ordering, handle TripWire from input processors during preparation, and portonInputAvailable/onOutputtool lifecycle hooks to the durable tool execution path. Removed stale test harness guards that were preventingisTaskComplete,actor,savePerStep, andproviderOptionsfrom reaching durable agent runs. These fixes enable 20+ scenario tests to run on the durable engine. (#18806)Fixed replay ordering on pull-mode transports (e.g. Redis Streams): history events are now delivered before live events, offsets are enforced on the live path, suppressed duplicates are acknowledged so persistent transports stop redelivering them, and ack/nack handles are preserved for buffered events. (#18479)
Added optional filter arguments to
Dataset.listExperiments()andDataset.listExperimentResults(). The storage layer already accepted these filters — they are now reachable from theDatasethandle. All new parameters are optional and existing callers are unaffected. (#18769)Before:
After:
listExperimentsaccepts:targetType,targetId,agentVersion,status, tenancyfilters.listExperimentResultsaccepts:traceId,status, tenancyfilters.Enables baseline vs variant read patterns without client-side filtering or bypassing
Dataset.Added optional tenancy arguments to
getDataset,updateDataset, anddeleteDataset. (#18750)You can now pass
organizationIdandprojectIdto scope dataset reads, updates, and deletes to a specific tenant. Reads and updates against a dataset in a different tenant throwDATASET_NOT_FOUND(surfaced as a 404 over HTTP). Deletes silently no-op on a tenancy mismatch — matching the existing "delete non-existent id is a no-op" semantics so cross-tenant existence is never leaked via error timing or status.Example
Fixed RequestContext leaking auth tokens onto scorer_run span input. Added serializeForSpan() to RequestContext so deepClean uses a safe snapshot instead of walking the internal registry Map. Also fixed the MastraScorer.run() call site to pass the serialized snapshot into the span input. (#18776)
Pushed remaining dataset read filters and pagination down to storage. (#18710)
DatasetsManager.list({ filters })now acceptstargetType,targetIds(overlap/union semantics), andname(substring, case-insensitive) in addition to the existing tenancy and candidate filters. Filtering is pushed down to the storage layer so callers no longer have to post-filter results.Storage adapters must also be upgraded to the versions listed below to honor the new filters. If a caller is on this version of
@mastra/corebut on an older storage adapter, the newtargetType/targetIds/namefilter keys are silently ignored by the adapter — no runtime error, but the filter has no effect and every dataset in the tenancy is returned.Dataset.listItems({ version, search, page, perPage })now appliessearchand pagination at the storage layer whenversionis provided alongside any of those. Previously they were silently dropped wheneverversionwas set. The return shape is unchanged: passing onlyversionstill returns a bareDatasetItem[]snapshot; passingsearch,page, orperPage(with or withoutversion) returns the paginated{ items, pagination }shape. The bare-array branch is marked@deprecated; prefer passingpage/perPageto always receive the paginated shape.Fixed SystemPromptScrubber
processOutputStreamswallowing TripWire errors when strategy isblock. The abort call now correctly propagates the TripWire to halt the agent stream, matching the existing behavior inprocessOutputResult. (#18794)Fixed five DurableAgent behavioral parity gaps with the regular Agent loop: (#18712)
goalStephas been ported into the durable workflow, reading goal config, running completion scorers, and emitting goal chunks — matching the regular agent's behavior.processLLMRequestnow work on durable agents, short-circuiting the model call and replaying cached chunks.toModelOutputon successful tool results under a MAPPING observability span and normalize the output to AI SDK format, matching the regular agent's behavior.onInputStartandonInputDeltacallbacks on tool definitions are now invoked during durable agent streaming, and client-tool observability spans are created for tool input streaming.DurableAgentnow matchesAgentfor several per-step behaviors that were silently degraded on the durable path: (#18693)autoResumeSuspendedToolsis enabled.BackgroundTaskManagerget the background-task guidance prompt injected before each LLM call.supportedUrls(including async resolvers) is honored consistently for both regular and durable runs.modelSettings.headers) merge in a single documented order and are case-normalized so call-time values reliably override.prepareStepand input-processor overrides — includingmodel,tools,activeTools,providerOptions,modelSettings,structuredOutput, andworkspace— apply identically on both paths.Durable agents now honor
onIterationCompletecallback return values and delegation bail signals in the loop predicate, closing three behavioral parity gaps with the regular agent: (#18707)onDelegationCompletehook callsctx.bail(), the durable loop now stops at the next predicate evaluation instead of continuing indefinitely. ThedelegationBailedflag propagates throughDurableAgenticExecutionOutputandbaseIterationStateSchema.onIterationCompletecallback dispatch — The durable predicate now callsonIterationCompletedirectly (read fromglobalRunRegistry) and honors its return value:{ continue: false }stops the loop,{ continue: true }forces continuation whenmaxStepsallows, and{ feedback }injects a user message for the next LLM turn.pendingFeedbackStop) —onIterationCompletereturning{ continue: false, feedback: '...' }now schedules exactly one more LLM turn before stopping, matching the regular agent's behavior. ThependingFeedbackStopflag is persisted inbaseIterationStateSchemaacross iterations.Signal drain (bugs 5 and 11) is deferred —
DurableAgentdoes not yet participate inagentThreadStreamRuntimeand has nosendMessage/ signal infrastructure.Scenario tests
delegation-complete-bailandstop-condition-long-loopnow run on the durable engine. Theaimock-scenarioharness no longer dropsstopWhen,delegation, oronIterationCompletefor durable runs.Background-dispatched sub-agent delegations no longer send null tool-message content (#17791)
When a sub-agent invocation (an
agent-<name>tool) is dispatched as a background task, the agentic loop hands the sub-agent tool'stoModelOutputthe placeholder string fromtool-call-step.ts("Background task started...") instead of theagentOutputSchemaobject.toModelOutputreadoutput.text, which is undefined for that string, so the supervisor's next request carried arole: "tool"message with null content. Providers that validate tool content (e.g. Anthropic) reject that with a 500, breaking the supervisor turn whenever it backgrounds a sub-agent (backgroundTasks.tools: { someSubAgent: { enabled: true } }).toModelOutputnow uses the placeholder string directly when the output is a string, so the tool message always carries non-empty content and the supervisor can acknowledge the dispatch and continue while the sub-agent runs in the background.Fix evented workflow parallel steps re-running the wrong branch on restart. The parallel processor built each branch's execution path from its position in the filtered (active-only) list instead of its real index, so restarting a parallel step whose active branches were not a contiguous prefix routed to the wrong branch (and skipped the intended one). Branches are now addressed by their real index. Closes #18754. (#18755)
createCodingAgentnow only includes the defaultTaskSignalProviderwhenmemoryis configured. Previously it always wiredTaskSignalProvider, whoseTaskStateProcessorrequires a memory-backed thread — causing a hard error in memoryless contexts. The provider is merged into caller-provided signals when memory is present, so custom signal providers don't drop task tracking. (#18728)Fixed approved and declined tool approvals not round-tripping on recall. (#18583)
After a
requireApprovaltool call was approved or declined,memory.recall()lost the decision: a decline was stored as a normal successful result (state: 'result'with the rejection string) and an approval dropped the approval entirely. Now:state: 'output-denied'withapproval: { id, approved: false, reason }, so recalled AI SDK v6 UI parts render asoutput-denied. In v4 and v5 (which have no denied state) the call downgrades to a singleoutput-available(v5) / result (v4) part whose output is the decline reason — so the agent's onFinish memory save no longer throwsToolInvocation must have a result.approval: { id, approved: true }alongside the result, so v6 UI parts carry the approval.Approved and declined decisions now round-trip on recall consistently for both standard agents and durable agents (
DurableAgent, including the Inngest durable agent).Live approve/decline already worked; this was a write-path persistence gap. Fixes #17218.
Fixed reasoning text being lost in AIV4Adapter and stream-chunk assembly at the end of the turn (#18534)
Tenancy-scope experiments
getByIdanddelete*onExperimentsStorage. (#18770)ExperimentsStorage.getExperimentById,getExperimentResultById,deleteExperiment, anddeleteExperimentResultsused to key on the primary id alone, so any caller who knew the id could read or delete the row regardless of tenant. All four now accept an optionalfilters: { organizationId?, projectId? }argument that is enforced on every adapter (inmemory, libsql, pg, mysql, mongodb, spanner):get*returnsnullat the storage layer.delete*is a silent no-op.WHEREon the DELETE, an atomic gate + delete inside a transaction, or a scoped subquery for the results cascade). A concurrent tenant swap of the same id between a pre-check and the DELETE cannot let a scoped delete hit another tenant's row.Both behaviors match how a missing id already responds, so existence does not leak through error timing or messages.
The same atomic-DML pattern is also applied to
DatasetsStorage.deleteDatasetacross all 5 store adapters, closing a TOCTOU window between the pre-check and the parent DELETE that was introduced when tenancy filters were originally added.Dataset.getExperimentand the shared experiment-ownership gate onDatasetnow forward the dataset's tenancy scope to storage, so experiment reads and downstream mutations (list results, update result, delete experiment) reached through a dataset handle are automatically scoped to the owning tenant.Legacy calls that omit
filtersare unchanged, so this is fully backwards-compatible.Fixed a TypeScript error where auth provider instances (for example
new MastraAuthWorkos()) could not be assigned toserver.authorstudio.auth, failing withProperty '#private' is missing(#18682). (#18796)Auth providers are now typed with a new structural
IMastraAuthProviderinterface (exported from@mastra/core/serverand@mastra/auth), so provider packages no longer need a shared class identity with@mastra/core.CompositeAuthalso accepts anyIMastraAuthProviderimplementation. No code changes are required:Updated the ws dependency to ^8.21.0 to pull in fixes for an uninitialized memory disclosure (GHSA-58qx-3vcg-4xpx) and a memory exhaustion denial-of-service (GHSA-96hv-2xvq-fx4p) in the WebSocket server. (#18789)
Fixed an internal Mastra instance leaking a scorer hook onto a shared, process-wide emitter. Agents that use a Workspace (or any unwired agent run) built a throwaway internal Mastra whose scorer hook was never removed, so it kept firing on every scorer run and flooded logs with "scorer not found" errors. The scorer still ran correctly on the real Mastra — the noise came from the orphaned handler, which is now released on teardown. (#18763)
Scoped
getDatasetByIdanddeleteDatasetto tenancy filters when the caller passesorganizationId/projectId. (#18750)The adapters now push the tenancy predicate into the SQL/query when the new optional
filtersargument is present. Legacy calls that omit tenancy are unchanged. On mismatch,getDatasetByIdreturnsnullanddeleteDatasetis a silent no-op — the cascade delete (dataset items and versions) is gated by a scoped parent pre-check, so cross-tenant data is never touched.Added optional
organizationIdandprojectIdquery parameters to the dataset routes. (#18750)GET /datasets/:datasetId,PATCH /datasets/:datasetId, andDELETE /datasets/:datasetIdnow accept optional tenancy query parameters. When provided, they are forwarded tomastra.datasets.get/.deleteand the operation returns 404 if the dataset does not belong to the requested tenant. Requests that omit the query parameters keep their existing behavior.Example
Fixed durable agents to no longer persist
modelSettings.headersto durable storage. Headers (which may contain sensitive API keys or auth tokens) are now stripped during serialization and kept in-process on theRunRegistryEntry, then merged back at LLM execution time. (#18751)Also fixed missing model-config-level headers in the durable header merge pipeline.
Fixed subagent delegations wasting an LLM call on title generation. When a supervisor agent's Memory has generateTitle enabled and delegates to a subagent with no memory of its own, the subagent inherited the supervisor's Memory instance and its generateTitle setting, firing an extra title-generation call for every ephemeral delegation thread that no one ever sees. Title generation is now treated as a top-level thread concern and is suppressed for these ephemeral subagent threads. To generate titles for a subagent's own threads, give that subagent its own memory configuration. (#18761)
Updated dependencies [
1042cb4]:v1.48.0Compare Source
Minor Changes
Renamed the AgentController interval API.
heartbeatHandlersis nowintervalHandlers, theHeartbeatHandlertype is nowIntervalHandler, and theremoveHeartbeat()/stopHeartbeats()methods are nowremoveInterval()/stopIntervals(). This better reflects that these are fixed-interval background tasks, not liveness pings, and is distinct from the unrelatedmastra.heartbeatsscheduled-agent feature. (#18665)Before
After
Added optional
maxStepstoScorerJudgeConfigandGoalConfig, letting callers control the internal judge agent's agentic-loop iteration limit instead of relying on the implicit default of 5. Also fixed judge agent not receiving Mastra registration, which caused the observer's API key resolution to fail silently. (#18544)Added optional
maxStepstoScorerJudgeConfig, letting callers control the internal judge agent's agentic-loop iteration limit instead of relying on the implicit default of 5. (#18544)Added
createCodingAgentfactory and a reusablebuildBasePromptso other projects can build a coding agent on top of the same defaults MastraCode uses. (#18695)The factory wires sensible, portable defaults that you can override per field:
process.cwd()(setbasePath, pass your ownworkspace, or passworkspace: undefinedto opt out entirely).TaskSignalProviderso a task list persists across turns.ECONNRESETand bad-request errors, plus prefill and provider-history compatibility processors.buildBasePromptis parameterized withproductName,coAuthorName(both default to "Mastra Code"), andcoAuthorEmail(defaults to "noreply@mastra.ai"), so you can brand the system prompt and commit trailer without forking it.Added heartbeats: schedule an agent to run on a recurring cron, either inside an existing conversation thread or on its own. (#18184)
A heartbeat fires a prompt to an agent on a schedule. When it has a thread, the run is delivered into that thread as a normal agent signal, so anything watching the thread sees it like any other message; without a thread, the agent just runs in isolation. Each heartbeat has its own id and an optional
name, so one agent or thread can have several heartbeats with different schedules and prompts. The id is generated for you, or you can pass your ownidtocreatefor a stable handle (it's normalized tohb_<slug>). Heartbeats are persisted, so they keep firing across process restarts with no extra setup.The same CRUD is available over HTTP through
@mastra/server(under/api/heartbeats) and as top-level methods on the@mastra/client-jsclient (client.createHeartbeat,client.getHeartbeat,client.listHeartbeats, etc.).Lifecycle hooks
React to heartbeat runs via
heartbeaton theMastraconstructor. It's a single hook bundle that runs for every agent's heartbeats; each hook receives the firingagentIdso you can branch on it.prepareresolves fire-time parameters (for example, creating a fresh thread per fire), andonFinish/onError/onAbortmirroragent.stream.Signal shaping
A heartbeat fire surfaces to the agent as a signal. By default it uses the
notificationtype and renders as<heartbeat>…</heartbeat>; overridesignalTypeandtagNameto change either.ifActiveandifIdlemirror theagent.sendSignaloptions shape ({ behavior, attributes }, plusstreamOptionsonifIdle) and stay JSON-serializable so they persist with the schedule.ifIdle.streamOptionscurrently acceptsrequestContext, which is rehydrated onto the woken run. Top-levelattributesare rendered on the signal tag, and top-levelproviderOptionsare merged into the signal payload on every fire.add OM-managed working memory (#18654)
Adds
observationalMemory.observation.manageWorkingMemoryso the Observer can update working memory automatically instead of requiring the main agent to call the working memory tool.This option adds
WorkingMemoryExtractor, defaultsworkingMemory.agentManagedtofalse, and defaultsworkingMemory.useStateSignalstotruewhen working memory is enabled. SetworkingMemory.agentManaged: trueto keep the main agent's working memory tool and instructions enabled.Added file-based agents: define an agent by file convention under
src/mastra/agents/<name>/alongside agents created withnew Agent(). (#18609)A directory becomes an agent when it has a
config.tsorinstructions.md. The directory name is the agent name.instructions.mdsupplies the instructions,tools/*.tssupply tools,skills/supplies skills (acreateSkill()module, a packagedSKILL.mddirectory, or a flat<skill>.md), and amemory.tsdefault export supplies the agent'smemory(config.memorywins if both are set). Each file-based agent also gets a workspace by default (contained filesystem + shell sandbox rooted at a per-agentworkspace/dir); customize it with aworkspace.tsdefault export orconfig.workspace. Both styles register into the same Mastra instance and show up together in Studio, the server, and the bundler.Before
After (file-based, optional)
A file-based agent can also declare subagents under
agents/<name>/subagents/<childId>/, using the same directory layout as an agent (config.ts,instructions.md,tools/,skills/,workspace.ts/workspace/). Each subagent is assembled independently and wired into the parent'sagentsmap, so the loop exposes it as a delegation tool named after the directory. A subagent'sconfig.tsmust set a non-emptydescription(build error otherwise), subagents inherit nothing from the parent, and they are one level deep (a nestedsubagents/directory is ignored with a warning). A subagent id colliding with a parent tool key or another subagent id is a build error; an id also present inconfig.agentskeeps theconfig.agentsentry with a warning.Code-registered agents win on name collisions, and a
config.tsthat exportsnew Agent()is used as-is (its siblinginstructions.md,tools/, andsubagents/are ignored with a warning), so existing projects are unaffected.The core API surface is
agentConfig()plus theassembleAgentFromFsEntry()/Mastra.__registerFsAgents()helpers that turn a discovered directory into a registered agent. Directory discovery itself is performed by the build pipeline; importing themastrainstance directly as a library does not scanagents/<name>/directories, so register those agents in code if you need them outside the build pipeline.support inline JSON prompt injection (#18652)
Added
structuredOutput.jsonPromptInjection: 'inline'toappend JSON schema instructions to the latest user message
instead of the system prompt. This helps keep the system
prompt stable on providers that cache prompt prefixes.
Added storage-backed discovery of suspended agent runs, so human-in-the-loop approval UIs can recover a pending run after a page refresh or server restart. (#17898)
agent.listSuspendedRuns()lists runs waiting on a tool-call approval or on a tool that calledsuspend(). Unlike the in-memorygetActiveThreadRunId(), it reads from storage, so it works after a restart and across multiple server instances:Supports
threadId/resourceId/date filters and pagination, mirroringlistWorkflowRuns(). The same surface is exposed over HTTP asGET /agents/:agentId/suspended-runsand on the client SDK asagent.listSuspendedRuns(); server-enforced request-context values take precedence over client query parameters, so clients cannot list runs outside their scope.sendToolApproval()now falls back to this storage-backed discovery when no active run is found in memory for the thread, so approvals keep working after a restart. If several suspended runs match, it throws an error asking for atoolCallIdto disambiguate.Why: approval UIs previously had no public way to recover a suspended run after a refresh or restart, forcing apps to parse internal workflow snapshots.
Patch Changes
Update provider registry and model documentation with latest models and providers (
b9a2961)Fixed thread metadata being lost when a processor or working memory writes to it during an agent run. The thread is re-saved when the run finishes, and it was using a stale in-memory snapshot that overwrote any metadata written mid-run via updateThread. The agent now re-reads the latest persisted thread before that save, so mid-run metadata is preserved. Affects all storage backends (Postgres, LibSQL, and others). Fixes #16216. (#18152)
Fixed find_files and grep tools to always exclude .git directory contents — the .git directory is now skipped at the traversal boundary in both tools since its internals are never useful and waste tokens. Also fixed pipe-separated exclude patterns in find_files (e.g. ".git|node_modules") to work correctly, matching tree's -I flag behavior. (#18548)
DurableAgentnow matchesAgentbehavior in three places where the durable loop previously diverged: (#18677)isTaskCompletescorers receiverequestContextascustomContext, so the same scorer code works on both agents. Only JSON-serializable entries fromrequestContextare forwarded; non-serializable values are dropped. Do not store secrets inRequestContextif you persist durable agent snapshots.web_search) resolve and execute when invoked by the model, instead of surfacing asToolNotFoundError.messageId, matching the non-durable loop and unblocking downstream consumers (signal drains, audit logs, replay) that key off message identity.add agent reference to processor execution context (#18651)
Fix in-memory workflow storage
getWorkflowRunByIdreturningnullwhenworkflowNameis omitted.workflowNameis optional in the storage contract and the pg/libsql adapters match byrunIdalone when it is not provided, but the in-memory store always comparedworkflow_name === workflowName, which never matched for an undefined name. It now matches byrunId, only filters byworkflowNamewhen provided, and returns the most recent run for parity with the persistent adapters. Closes #18585. (#18586)Fix in-memory observability
listTracesignoring thestartExclusiveandendExclusiveflags onstartedAt/endedAtfilters. Exclusive date-range bounds now drop a trace that sits exactly on the boundary, matching the pg/libsql adapters (and the in-memory log/metric filters). Closes #18635. (#18675)Fix in-memory scores store
listScoresByScorerIdreturning scores in insertion order instead of newest first. The pg and libsql adapters order bycreatedAt DESC, and the siblinglistScoresBySpanalready does, so the in-memory store now sorts the same way before paginating. Closes #18618. (#18619)add observational memory extractors (#18653)
Introduces a public Extractor API for Observational Memory
with inline XML extraction and structured follow-up modes.
Includes built-in extractors for current task, suggested
response, and thread title. Persists extracted values into
thread OM metadata with key-level merging and carry-forward
into future observer/reflector prompts.
Fix a polynomial ReDoS in the model gateway error matcher. The
Missing .+ environment variablepattern used to classify expected missing-auth errors could backtrack catastrophically on adversarial error messages; it now usesMissing [^ ]+ environment variable, which matches the same real messages without the ambiguous overlap. (#18680)Bring
InngestAgent(Inngest-backed durable agent) to parity withDurableAgentfor per-call execution options, abort handling, idle-aware resume, andgenerate(). (#18615)InngestAgent.stream()andresume()now accept the same execution-option surface asDurableAgent, includingstopWhen,activeTools,structuredOutput,versions,system,disableBackgroundTasks,tracingOptions,actor,transform,prepareStep,isTaskComplete,delegation, function-formrequireToolApproval, and the lifecycle callbacksonAbort/onIterationComplete. Closure-shaped options (prepareStep,transform, function-formisTaskComplete/requireToolApproval,stopWhencallbacks) continue to work in-process; they degrade after a worker hop the same way they do for in-memoryDurableAgent.@mastra/corere-exportsglobalRunRegistryandrunResumeDurableStreamUntilIdlefrom@mastra/core/agent/durableso durable-agent integrations can share the same registry and idle-wrapper plumbing.fix: prevent partial gateway sync from corrupting provider registry (#18545)
Amazon Bedrock models now appear under their own
amazon-bedrock/<model>provider in the model picker instead of themastracode/amazon-bedrock/<model>namespace. Bedrock is resolved through a dedicated Amazon Bedrock gateway that authenticates with the AWS credential chain (SigV4) and surfaces models from the public models.dev catalog. Saved model selections using the previousmastracode/amazon-bedrock/...IDs are still resolved at runtime, so existing config keeps working. (#17937)Fixed gs:// and s3:// file/image references being downloaded and corrupted into data: URIs during durable agent execution. The durable LLM step now forwards the model's supportedUrls (matching standard execution), so URLs a provider fetches natively (e.g. Vertex gs://) pass through as references instead of failing with "Failed to download asset" or being base64-wrapped. (#18649)
Fixed background task execution metadata updates so they no longer rewrite the model-visible tool invocation state. (#18556)
Fixed 'Type instantiation is excessively deep' (TS2589) errors that occurred when defining workflows with Zod schemas. Workflow and step type inference is now significantly faster and no longer causes TypeScript to crash or report depth errors. (#18608)
Reduce repeated schema work during sub-agent tool conversion for more stable memory usage. (#18566)
Scripts using Mastra no longer hang after completing their work. The scheduler timer that polls for due schedules previously kept the Node.js event loop alive, preventing process exit even when all work was done. The timer now allows the process to exit naturally. (#18713)
Fixed buffered observation extraction metadata so stored OM chunks keep extracted values and extraction failures across memory storage adapters. (#18655)
Fixed custom model gateways being overridden by default gateways. GatewayManager now deduplicates gateways by ID (first-wins) so custom gateways take precedence over defaults. Narrowed the auth-availability check to only swallow expected missing-credential errors instead of all errors, so real gateway failures surface during debugging. (#18602)
Fixed channel broadcasting so agent runs on a channel-backed thread post back to the channel even when they did not start from an inbound platform message. Previously only runs triggered by an incoming Slack/Discord/etc. message would render to the channel; heartbeat, Studio, and custom UI runs were silently dropped. The channels output processor now reconstructs the channel destination from the thread itself, so any run on a channel-backed thread delivers its output. (#18630)
Updated dependencies [
d0702ee,9feeaa0,213feb8]:v1.47.0Compare Source
Minor Changes
Added support for AI SDK v7 models (
LanguageModelV4). You can now pass any AI SDK v7 provider model directly to an agent, alongside the existing AI SDK v4, v5, and v6 support. (#18477)Mastra detects the model's specification version automatically, so mixing models from different AI SDK versions across your agents continues to work without any extra configuration.
Finished closing the gap between
DurableAgentandAgent. After this change the durable agent surface mirrors the in-process agent's stream, resume, and generate APIs. (#18508)What's new
abortSignalonstream()andresume(), plusresult.abort()onstream(),resume(), andobserve().result.abort()onstreamUntilIdle()fans out to every inner run.untilIdleonresume()(it already existed onstream()), using the sharedrunWithIdleWrapperso both paths drive the same idle loop.DurableAgent.generate()andDurableAgent.resumeGenerate()wrapstream()/resume()and resolve aFullOutputeven when the run suspends mid-flight.delegationcallbacks (onDelegationStart,onDelegationComplete,messageFilter) are forwarded toconvertToolsat prepare time and baked into sub-agent tool wrappers.clientToolsandtoolsetssurvive in-process resume via the run registry (cross-process resume still falls back to the agent's static tools).ON_SCORER_RUNConfiguration
📅 Schedule: (UTC)
🚦 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 this update again.
This PR was generated by Mend Renovate. View the repository job log.