Skip to content

October 1, 2026

Choose a tag to compare

@PaulieScanlon PaulieScanlon released this 05 Oct 09:30
· 197 commits to main since this release

Highlights

Default Agent Error Recovery (Repair-first + Safe Retries)

Agents now automatically recover from common provider failures with three default error processors (ProviderHistoryCompat, PrefillErrorHandler, StreamErrorRetryProcessor) enabled by default, repairing history/prompt before retrying. You can still fully control or disable defaults via errorProcessors and errorProcessorDefaults: false.

Better Tool-Pause UX: New tool-call-resumed Stream Chunk

Streaming now emits a tool-call-resumed chunk when a suspended or approval-gated tool call resumes (durable and non-durable), allowing clients to reliably mark questions/approvals as answered before the tool-result arrives. The change is wired through @mastra/ai-sdk and @mastra/react (useChat) so UIs can clear pending tool states correctly.

Google Workspace Toolsets + Binary Proxy Responses in @mastra/connect

@mastra/connect adds Google Docs/Drive/Sheets toolsets (edit/export docs, manage Drive files/permissions, read/write Sheets) for agents running through Mastra Cloud. The platform proxy now supports binary responses via responseType: 'arraybuffer', unlocking document exports and other binary-download actions.

Observational Memory Can Show Attachments to the Model

@mastra/memory adds viewAttachment to the observational memory recall tool so models can see the actual attachment (native media parts for images/PDFs) instead of only a description. Attachment references in recall results are also fixed so agents can correctly reuse prior files/images.

Reliability & Scale Fixes for Durable/Evented Execution

Durable agents and evented workflows get multiple correctness fixes: output-processor retries now work for durable runs, resumed tool calls can run in parallel again, and long-running evented steps no longer double-run due to redelivery (heartbeat + lease fencing). Large thread history loading is also improved from quadratic to linear time, dramatically reducing latency on big threads.

Breaking Changes

  • Durable streams no longer emit a separate tripwire chunk when an output processor blocks; use finishReason === 'tripwire' and output.tripwire instead.

Changelog

@mastra/core@1.73.0

Minor Changes

  • Every agent now recovers from transient provider failures, assistant-prefill rejections, and provider history incompatibilities with no configuration. Three error processors — ProviderHistoryCompat, PrefillErrorHandler, and StreamErrorRetryProcessor — are on by default, in the order that repairs history before anything retries. A ProviderHistoryCompat in errorProcessors now also repairs the outbound prompt before the provider sees it, instead of only reacting to a rejection. (#24473)

    You stay in control of the list:

    // Replace one default: your instance with the same id takes its slot.
    // Retries above 3 also need maxProcessorRetries.
    new Agent({ ..., errorProcessors: [new StreamErrorRetryProcessor({ maxRetries: 5 })], maxProcessorRetries: 5 })
    
    // Run only your own processors — none of the defaults are merged in.
    new Agent({ ..., errorProcessors: [myProcessor], errorProcessorDefaults: false })
    
    // Run with no error processors at all.
    new Agent({ ..., errorProcessorDefaults: false })

    errorProcessorDefaults: false is the only opt-out: an empty errorProcessors list merges like any other and still gets the defaults.

    The default retry processor retries transient failures only. Transient failures recover through provider isRetryable metadata, the built-in OpenAI stream-error matcher, or the connection-reset matcher, while deterministic failures — a rejected structured-output attempt, a validation error, or any HTTP 400 the repair processors cannot fix — surface immediately instead of being replayed unchanged. Pass StreamErrorRetryProcessor({ retryUnknownErrors: true }) in errorProcessors to retry unmatched errors. createCodingAgent keeps its shipped behavior, retrying both unmatched errors and bad-request responses, as it always has.

    Error-processor retries are bounded by a safety cap of 3 per turn when you don't set maxProcessorRetries; the defaults stop well below it on their own. The "errorProcessors are configured without an explicit maxProcessorRetries" warning now fires only when you configured error processors yourself, not for the framework defaults.

  • Export findGatewayForModel and getGatewayId from @mastra/core/llm so callers can check which registered gateway the model router would pick for a model ID. Like the router, findGatewayForModel skips disabled gateways. (#25482)

    import { findGatewayForModel, getGatewayId } from '@mastra/core/llm';
    
    const gateway = findGatewayForModel('acme/fast-1', Object.values(mastra.listGateways() ?? {}));
    console.log(getGatewayId(gateway));
  • Added a tool-call-resumed stream chunk. It is emitted when a suspended or approval-gated tool call resumes, on both regular and durable agents, and comes before that call's tool-result. payload.kind tells you whether it was a suspension or an approval. Clients can now tell that a suspension was answered even when a sub-agent suspended through a delegation call and the delegation's later result replaces the tool output. Fixes #24280. (#25491)

    const stream = await agent.resumeStream({ answer: 'yes' }, { runId, toolCallId });
    
    for await (const chunk of stream.fullStream) {
      if (chunk.type === 'tool-call-resumed') {
        markAnswered(chunk.payload.toolCallId);
      }
    }
  • Invalid tool-call IDs on Anthropic models are now rewritten in the outbound request, so they no longer reach Anthropic and no longer require a failed call to recover. Persisted history keeps its original IDs. The rule's reactive repair (errorPatterns and fix) stays as the fallback for Claude served through a provider the preemptive check doesn't recognize, such as Vertex-hosted Claude, and for placements outside the agent's prompt path. (#24505)

  • Added an optional resolveSubagentModel(modelId, { requestContext }) option to AgentControllerConfig. Subagent models can now resolve with the calling run's request context, so custom providers and tenant credentials work for subagents the same way they do for the main agent. The context passed in doesn't include the parent run's thread or resource IDs. (#25482)

    const controller = new AgentController({
      // ...
      resolveSubagentModel: (modelId, { requestContext }) => resolveTenantModel(modelId, requestContext),
    });

Patch Changes

  • Fixed aborting an agent run taking up to 10 seconds when the provider reported low remaining rate-limit tokens. The pause between steps now ends as soon as the run's abortSignal fires. (#25648)

  • Update provider registry and model documentation with latest models and providers (42b8761)

  • Fixed trace aggregation returning a server error when a having filter used includes or notIncludes. These operators are now rejected with a validation error. (#25607)

  • Fixed saving builder workflows with classifier steps when the model sends null for maxRetries or providerOptions. These values are now treated as omitted, the same as retries and metadata, instead of failing validation. (#25531)

  • Fixed startAsync so it returns only after workflow execution is durably recoverable. Fixes #24585. (#24673)

  • Fixed misleading tool input validation errors. When a model sent null for optional fields and the call still failed for another reason, the error listed the null fields as problems and hid the real cause. Errors now report only the issues that remain after null values are removed, so models can fix the actual problem on the next attempt. (#25656)

  • Fixed agent controller sessions losing the signed-in user when memory is configured as a function. Cloning a thread, forking a subagent, and opening a thread's history subscription (opening a session, switching or creating a thread, sending a message or notification, resuming a suspended tool) now pass the caller's request context to the memory factory. If the session already has the thread open, the open subscription is reused and its history keeps the memory it resolved when it opened. Per-user memory now resolves correctly instead of failing with a missing user context. (#25082)

    Pass the caller's context when cloning, switching, or creating a thread:

    await session.thread.clone({ sourceThreadId, requestContext });
    await session.thread.switch({ threadId, requestContext });
    await session.thread.create({ title, requestContext });
    await session.thread.delete({ threadId, requestContext });

    Deleting a thread also removes it from the caller's resolved memory, so a cloned thread's messages are not left behind.

    A message sent while a run is active joins that run and uses the memory resolved for the caller who started it. The next run resolves memory with the context of the caller whose message starts it.

    Also in: @mastra/server@1.73.0

  • Fixed durable agents stopping when an output processor asks for a retry. abort(reason, { retry: true }) in processOutputStep now calls the model again with the reason as feedback, up to maxProcessorRetries (set on the agent or per call), like regular agents do. (#25585)

    Fixed durable agent streams ending early when an output processor blocks a response. The stream now ends with a finish chunk, finishReason is 'tripwire', onFinish is called, and output.tripwire holds the reason. Durable streams no longer emit a separate tripwire chunk for this case, matching regular agents. See #22980.

    Migrating from the tripwire chunk

    If you listened for the tripwire chunk on a durable stream, read finishReason and output.tripwire instead:

    // Before
    for await (const chunk of output.fullStream) {
      if (chunk.type === 'tripwire') console.log(chunk.payload.reason);
    }
    
    // After
    for await (const chunk of output.fullStream) {
      // render chunks as usual
    }
    if ((await output.finishReason) === 'tripwire') {
      console.log(output.tripwire?.reason);
    }
  • Fixed durable agents reporting retryCount: 0 to processor hooks after an API-error retry. Hooks like processInputStep, processLLMRequest and processOutputStep now see the same retry count as with a regular Agent. (#25642)

  • Fixed long-running evented workflow steps running twice when the broker redelivers the step event before the step finishes. Workers now send a heartbeat while a step runs, so the broker does not hand the event to another worker. Each step run is also fenced with a lease, so a redelivered copy is dropped while the original is still running. Redis Streams and Valkey Streams support the heartbeat. Steps should still be idempotent, because a worker crash can still cause a step to run again. (#24769)

    Also in: @mastra/redis-streams@0.6.1, @mastra/valkey-streams@0.5.3

  • Fixed run.timeTravel() rejecting array inputData when targeting a top-level .foreach() step. Each array element is now validated against the step's input schema, so Studio's "Run next step" works at foreach loops, including for Inngest workflows. (#25626)

    Also in: @mastra/inngest@1.10.2

  • Fixed durable agents running output processors twice on tool results. A processOutputStream processor now sees each tool result, tool error, and denied tool call once, so counters, billing, and edits to tool results are no longer applied twice. Fixes part of #22980. (#25578)

  • Use Web Crypto for portable identifiers, random secrets, and asynchronous sandbox profile hashing (#25462)

  • Fixed slow loading of long conversation histories. Loading stored messages took time that grew with the square of the thread length, so a thread with 10,000 messages could block the server for several seconds on every load. Loading now grows linearly with the thread length. Fixes #24143. (#25061)

  • Tool approval and tool suspension requests now report whether they were actually accepted. Previously, approveTool() and respondToToolSuspension() always returned success, even when the decision was stale, a duplicate, or answered a question that was no longer pending. They now resolve to { ok: false, reason } in those cases, so you can tell an accepted decision from one that was ignored. (#25087)

    const ack = await session.approveTool(toolCallId, true);
    if (!ack.ok) console.warn(`Approval not applied: ${ack.reason}`);

    approveTool() and respondToToolSuspension() no longer retry automatically. A retried decision would be rejected as already handled, so an applied decision could be reported as ignored.

    Also in: @mastra/client-js@1.51.1, @mastra/server@1.73.0

  • Fixed evented workflows so concurrent resume calls continue a suspension only once. (#25458)

  • Fixed DurableAgent construction to preserve dynamic model resolution until request context is available. Wrapping an agent with a request-dependent model no longer resolves the model eagerly during startup. (#25359)

  • Reduced durable agent snapshot size by no longer saving the agent's system prompt on every step. Resume, tool approval, and trace rebuilds still use the copy kept in the run input, so behavior and traces are unchanged. (#25609)

  • Include threadId and resourceId on lightweight trace list rows so the Thread ID and Resource ID columns render when the trace query API is unavailable. (#25433)

    Also in: @mastra/clickhouse@1.22.1, @mastra/client-js@1.51.1, @mastra/duckdb@1.12.1, @mastra/playground-ui@60.1.0

  • Fixed filesystem storage writing MCP client config fields like name and servers onto the client record during update(). Only record-level fields are stored there now; config stays in versions. (#25646)

  • Fixed durable agents rebuilding a run on another worker, or after a restart, with the wrong request processors. The rebuilt run now uses the processors configured on the wrapped agent, so processors that rewrite the outbound model request keep running, and a per-call errorProcessors: [] still turns error processors off. (#24473)

  • Fixed evented workflow restarts that occur before the first step is saved. (#25389)

  • Fixed a follow-up message sent right after aborting a run replaying the aborted run. A new thread subscription no longer re-emits the aborted run's lifecycle events (such as a second agent_start) while that run is still shutting down. (#25641)

  • Fixed run.cancel() overwriting the status of a workflow run that had already finished. Canceling a run that ended as success, failed, canceled, tripwire or bailed is now a no-op, so its stored status is preserved. This applies to both the default and evented workflow engines, and to the POST /api/workflows/:workflowId/runs/:runId/cancel route. (#25414) (#25628)

  • Fixed stream.text and the last step's text resolving to an empty string when an agent has an output processor and the run stops via stopWhen on a step that contains both text and a tool call. Output processors that intentionally clear text still work as before. (#25381)

  • Fixed ToolCallFilter stripping a resumed run's own tool calls. When a tool suspended the agent (for example askUserTool) and the run was continued with resumeStream(), the filter treated the suspended tool call and its result as prior history and removed them from the model prompt. The model never saw its question or the user's answer, so it asked again and the run suspended forever. Tool calls made in the current run, including everything before a suspension, now stay in the prompt after resume. Fixes #24382 (#25566)

  • Fixed resumeStream running resumed tool calls one at a time under toolCallConcurrency: { strategy: 'called' }. Parallel-safe tool calls that paused together, such as sub-agent delegations, now resume in parallel. If one call pauses again, its siblings still continue. (#25490)

  • Fixed background workflow tools filling Redis with oversized progress updates (#25590). When a background workflow step called an agent, each progress update carried a full copy of the model request and message history, so a single update could reach 60MB. Progress updates now leave those copies out and no longer repeat the task's arguments, while progress information such as text, finish reason, and usage is still delivered. (#25606)

  • Fixed durable agents dropping custom resumeData on tool approval. When a caller approves a tool call with extra keys, for example sendToolApproval({ approved: true, resumeData: { approved: true, note: 'hello' } }), the durable agent now forwards that payload to the tool's execute through context.agent.resumeData, matching the non-durable agent. A bare { approved: true } is still not forwarded. Fixes #24561 (#25562)

  • Fixed LocalSandbox seeding a working directory with a mix of two checkpoint versions when snapshot() replaced the checkpoint during start(). The seed now retries until it copies one complete checkpoint. (#25528)

  • Fixed tool request context validation accepting invalid values when requestContextSchema is a Valibot schema. Valibot returns both a value and issues on failure, and the issues are now reported instead of being ignored. (#25644)

  • Fixed goals using up a run when the goal judge errors. A failed judge call (for example, a dropped network connection) still pauses the goal so it can be resumed, but the failed attempt no longer counts against the goal's run limit. Fixes #22446. (#25205)

@mastra/acp@0.4.2

Patch Changes

  • Generate SDK, pubsub, and workflow identifiers with Web Crypto while preserving synchronous behavior. (#25462)

    Also in: @mastra/claude@0.3.2, @mastra/cursor@0.3.2, @mastra/inngest@1.10.2, @mastra/openai@1.1.2, @mastra/redis-streams@0.6.1, @mastra/valkey-streams@0.5.3

@mastra/agentcore@0.5.1

Patch Changes

  • Generate workspace, integration, channel, and voice identifiers with Web Crypto without changing synchronous APIs. (#25462)

    Also in: @mastra/cloudflare-sandbox@0.5.1, @mastra/daytona@0.11.2, @mastra/discord@1.2.1, @mastra/docker@0.9.2, @mastra/livekit@0.4.2, @mastra/nestjs@0.2.32, @mastra/voice-aws-nova-sonic@0.2.3, @mastra/voice-google-gemini-live@0.14.13

@mastra/ai-sdk@1.10.6

Patch Changes

  • Mapped the new tool-call-resumed chunk to a data-tool-call-suspended part (or data-tool-call-approval part for approvals) with resumed: true and the same id. The part keeps the original suspend payload, args, and resume schema, so UIs mark the question as answered in place without losing it. (#25491)

    for (const part of message.parts) {
      if (part.type === 'data-tool-call-suspended' && part.data.resumed) {
        // The question in part.data.suspendPayload has been answered
      }
    }
  • Custom data-* chunks written with transient: true now keep that flag when streamed through @mastra/ai-sdk, so they reach onData without being saved into message.parts. (#25608)

@mastra/auth-studio@1.3.8

Patch Changes

  • Fixed local dev auth: MastraAuthStudio now falls back to organizationId in .mastra-project.json when neither the constructor option nor MASTRA_ORGANIZATION_ID env var is set. Running pnpm mastra dev in a project linked to a platform organization now pins AuthKit to that org and skips the WorkOS org picker for multi-org users, without requiring the env var to be exported locally. (#25583)

@mastra/clickhouse@1.22.1

Patch Changes

  • Fixed ClickHouse feedback and score aggregates returning a sum when count_distinct was requested. They now return the number of distinct values. (#25615)

  • Fixed ClickHouse score aggregates returning 0 instead of null when no scores match the filter, matching the other storage adapters. (#25607)

  • Read the results of the serial-cursor probe and counter warm-up queries in the observability store, so their connections are freed at once instead of staying busy until the client's request timeout. This removes waits of up to 30 seconds after init(). (#25613)

  • Generate storage identifiers with Web Crypto without changing synchronous storage interfaces. (#25462)

    Also in: @mastra/elasticsearch@1.4.3, @mastra/libsql@1.24.1, @mastra/mongodb@1.20.1, @mastra/mssql@1.10.1, @mastra/mysql@0.11.1, @mastra/oracledb@0.4.2, @mastra/pg@1.28.1, @mastra/redis@1.4.8, @mastra/spanner@1.9.1, @mastra/upstash@1.5.1, @mastra/valkey@0.2.4

@mastra/client-js@1.51.1

Patch Changes

  • Fixed Studio hiding processors that only implement processLLMRequest, such as ToolCallFilter. The processors API now reports an llmRequest phase for these processors, so they appear in the Processors page, sidebar, and picker. Studio disables direct execution of this phase because it operates on the provider prompt during an agent call. Direct API requests return a 400 error. (#25500)

    For example, GET /api/processors can return:

    {
      "tool-call-filter": {
        "id": "tool-call-filter",
        "phases": ["llmRequest"],
        "agentIds": ["my-agent"],
        "configurations": [{ "agentId": "my-agent", "type": "input" }],
        "isWorkflow": false
      }
    }

    Also in: @mastra/server@1.73.0

@mastra/code-sdk@1.10.0

Minor Changes

  • Added an opt-in experimental agent runtime for validating Mastra Code on durable and evented execution. (#25359)

    Before

    mastracode

    Mastra Code always used the standard coding agent.

    After

    MASTRACODE_EXPERIMENTAL_AGENT=durable mastracode
    MASTRACODE_EXPERIMENTAL_AGENT=evented mastracode

    The SDK now wraps the coding agent with the requested implementation, rejects invalid or unsupported configurations at startup, and reports the resolved workflow engine.

Patch Changes

  • Mastra Code now uses the shared error recovery defaults from @mastra/core. It still repairs rejected message history and assistant-prefill errors before it retries, and it keeps its own tuned retry settings for network and server errors. (#24473)

  • Subagents now resolve models the same way the main agent does, including custom providers and tenant credentials from the calling run. Model IDs owned by another registered gateway still go to that gateway. (#25482)

    Behavior change for Factory: tenant subagents no longer fall back to the server's environment API keys (such as ANTHROPIC_API_KEY). A subagent whose provider isn't connected for the signed-in account now fails with a missing-credential error, matching the main agent. Connect the provider or add an org credential for those accounts.

  • Fixed account switching and removal across multiple running Mastra Code instances. Each instance now uses the latest accounts, including in /login. (#25517)

    • Requests using automatic account routing retry on a remaining account when another instance removes the account they were using.
    • Requests routed to a specific account stop instead of switching to a different account when that account is removed. Applying that account no longer shows a notice on every prompt, but failover notices still appear.
  • Generate Factory, CLI, channel, and signal identifiers with Web Crypto while retaining synchronous interfaces. (#25462)

    Also in: @mastra/factory@0.19.0, @mastra/github-signals@0.5.1, @mastra/slack@1.7.1, @mastra/telegram@0.2.1

  • Fixed headless runs without thread options to start a fresh thread instead of reusing the current thread. (#25594)

@mastra/codemod@1.1.6

Patch Changes

  • Fixed the v1/agent-abort-signal codemod creating a duplicate abortSignal key when the call already had one at the top level. It now leaves those calls unchanged and asks you to resolve them manually. (#25617)

@mastra/connect@0.6.0

Minor Changes

  • Added Google Docs, Google Drive, and Google Sheets toolsets to @mastra/connect. Agents connected through Mastra Cloud can now edit Google Docs (including PDF/DOCX/HTML/text export), manage Google Drive files, folders, permissions, and shared drives, and read and write Google Sheets, alongside the existing Gmail and Google Calendar toolsets. (#25596)

    Added binary response support to the platform proxy. Tool templates that need to fetch binary payloads (file exports, image downloads) can now pass responseType: 'arraybuffer' on a proxy request; the response body is returned as an ArrayBuffer instead of being parsed as JSON. This unlocks document-export tools such as Google Docs' export-document, and any future providers that ship binary-download actions.

Patch Changes

  • Provider errors that nest their message as { "error": { "message": "..." } } (for example OpenAI) now include that message in the thrown error. A missing OpenAI batch now reports Provider request failed (404): No such batch: batch_abc123 instead of Provider request failed (404). (#25533)

@mastra/convex@1.6.1

Patch Changes

  • updateWorkflowState now resolves to undefined when the workflow run has no saved snapshot, matching the other storage adapters. It previously threw Workflow snapshot not found for runId …, which could surface as an unhandled error during a workflow resume. (#25534)

@mastra/daytona@0.11.2

Patch Changes

  • Fixed S3 mounts in Daytona sandboxes for buckets outside us-east-1 and for prefixes without a placeholder object. The s3fs mount now passes the configured region for request signing and enables compat_dir when a prefix is set. (#25600)

@mastra/deployer@1.73.0

Patch Changes

  • Generate server request and development identifiers with Web Crypto (#25462)

  • Improved deployer builds to apply internal module replacements consistently during dependency analysis and bundling. (#25573)

  • Fixed Bun workspace builds when packed dependencies conflict with source lockfiles (#24879). (#25575)

@mastra/deployer-sandbox@0.3.17

Patch Changes

  • Use Web Crypto to compute asynchronous install-input digests without changing the cache key. (#25462)

@mastra/docker@0.9.2

Patch Changes

  • Fixed DockerSandbox reporting its default image instead of the running container's image after reconnecting, in both getInfo() and the agent instructions. (#25622)

@mastra/e2b@0.12.3

Patch Changes

  • Fixed S3 mounts ignoring sessionToken, so temporary AWS credentials (for example from STS AssumeRole) now work. Previously only permanent access keys could mount a bucket. (#25563) (#25599)

  • Generate code-mode temporary file suffixes with Web Crypto. (#25462)

@mastra/editor@0.15.5

Patch Changes

  • Fixed editor.scorer.clearCache() leaving stored scorers registered on Mastra after they were loaded with a specific version (getById(id, { versionId }) or { versionNumber }). Clearing the whole cache now unregisters them, so a later default getById registers the latest scorer instead of staying stuck on the historical one. (#25544)

  • Builder agents keep their stability error processors on every supported @mastra/core version, including cores that predate the framework defaults. Adding a processor never costs the builder its recovery: (#24473)

    createBuilderAgent({ errorProcessors: [myProcessor] });
    // resolved: provider-history-compat, prefill-error-handler,
    // stream-error-retry-processor, myProcessor

    A caller's array merges with the builder's list, which runs in repair-first order. A caller instance with a default's id takes that default's slot. Other caller processors run after the defaults. An empty array keeps the defaults. errorProcessorDefaults: false opts out and runs the caller's list as given. A function-valued override passes through unchanged, so a callback must return every processor it needs. DEFAULT_BUILDER_ERROR_PROCESSORS is still exported.

@mastra/elysia@0.1.13

Patch Changes

  • Fixed createAuthMiddleware returning 401 for custom API routes registered with requiresAuth: false. When the helper was mounted on a path that also served a public custom route (for example app.use('*', createAuthMiddleware({ mastra }))), it re-marked that route as protected. Public routes, including pattern routes such as /webhooks/:id, now stay public without also being listed in authConfig.public. (#25560)

    Also in: @mastra/express@1.5.17, @mastra/fastify@1.5.17, @mastra/hono@1.7.15, @mastra/koa@1.7.17

@mastra/evals@1.10.5

Patch Changes

  • Fixed checks.matches scoring matching outputs as 0 when the pattern uses the g or y flag and the scorer runs over several items. (#25633)

@mastra/factory@0.19.0

Minor Changes

  • Added support for replacing the built-in Work and Review boards. Set includeDefaultBoards: false and install your own board with id work or review. A same-id board still errors while the built-ins are installed. Closes #23881. (#25595)

    new MastraFactory({
      storage,
      includeDefaultBoards: false,
      boards: [myWorkBoard],
    });

Patch Changes

  • Fixed retrying a failed Factory run after its work item moved to another phase. The retry is now refused (canRetry: false and a 409 decision_not_retryable), and a stale run already in the queue settles as superseded instead of starting a session for the old role and reporting success. (#25550)

  • Fixed the GitHub issues and pull request lists returning a 502 github_fetch_failed error when re-ingesting the listed items into Factory rules failed. The lists now load and the ingestion failure is logged. (#25663)

  • Fixed Factory reviews posting a verdict that contradicts their review text. (#25494)

    • The source-control review tool, which GitLab reviews use, now rejects a review whose Verdict: line does not match the approve or request-changes choice. It also rejects a review whose Reviewed head: is not the current merge request head.
    • GitHub review skills now write each review body to a file named after the reviewed commit. Before posting, they check the verdict line and reviewed head, and they delete the file afterwards. A review written for an earlier commit is no longer reposted on a newer one.
  • Fixed the Jira integration returning a generic 404 error, instead of the friendly not-found message, when commenting on a missing issue by key (e.g. ENG-404). (#25623)

  • Fixed an internal reconciliation timestamp (externalSourceMissingAt) leaking into work item metadata returned by the Factory API. (#25607)

  • Improved the option pickers in Factory settings (notifications, tool permissions, observe attachments) and the API key sharing choice. They now use one consistent segmented control with a sliding selection. Changing a tool permission now updates instantly instead of briefly disabling the control while it saves. If saving fails, the previous choice is restored and an error is shown. (#25570)

  • Fixed web OAuth device sign-in (GitHub Copilot, OpenAI Codex) telling a second concurrent poll to wait for the entire remaining sign-in window. It now retries after 250 ms while another poll is in progress. (#25527)

  • Factory now dismisses its own stale change requests when it approves a pull request. Previously, if an earlier Factory review requested changes and a later Factory review (from a different reviewer identity) approved the repaired PR, GitHub kept the PR blocked at "changes requested". Only change requests left by the Factory GitHub App before the approval are dismissed; human reviews are never touched. (#25610)

@mastra/google-drive@0.2.2

Patch Changes

  • Sign PKCS#8 Google Drive service-account JWTs with Web Crypto while preserving PKCS#1 key support. (#25462)

@mastra/inngest@1.10.2

Patch Changes

  • Fixed Studio's Approve and Decline buttons for Inngest agents. sendToolApproval() now resumes the suspended run on Inngest instead of failing with "could not find a suspended run". (#25557)

  • Fixed nested Inngest workflow and durable agent failures losing their error message. Callers now receive the real cause (for example step output size is greater than the limit) instead of {"stepId":"…","name":"Error"}. (#25598)

@mastra/libsql@1.24.1

Patch Changes

  • Fixed updateWorkflowState in the LibSQL store not updating the run's updatedAt, so updated runs looked stale in sorting and retention. (#25618)

@mastra/loggers@1.3.4

Patch Changes

  • Fixed FileTransport log queries returning no logs when the log file contains a malformed line. Malformed lines are now skipped and valid logs are still returned. (#25624)

@mastra/mcp@2.1.2

Patch Changes

  • Generate MCP continuation keys with Web Crypto (#25462)

@mastra/memory@1.34.0

Minor Changes

  • Added viewAttachment to the observational memory recall tool. Passing it with cursor and partIndex shows the attachment itself to the model instead of only describing it. Inline data such as base64 or data URIs is sent as a native media part. Attachments stored as remote URLs or provider file IDs, media types outside image/* and application/pdf, and payloads over 10 MiB come back as an explanation instead. (#25054)

    recall({ mode: 'messages', cursor: 'msg_123', partIndex: 0, viewAttachment: true });

Patch Changes

  • Generate observational-memory identifiers and digests with Web Crypto (#25462)

  • Fixed the observational memory recall tool dropping attachment references. Image and file parts now include their media type and the stored URL or provider file ID instead of only the filename, so agents can reuse an earlier attachment. Inline data such as base64 or data URIs is never printed, including media stored in earlier tool results. Fixes #23813. (#25054)

@mastra/modal@0.7.1

Patch Changes

  • Fixed ModalFilesystem copyFile and moveFile deleting the source when the destination is the same path. They now throw FileExistsError and leave the file untouched. (#25634)

  • Fixed ModalSandbox.clone() ignoring the workingDirectory override, so clones now use the requested directory instead of the template's. (#25607)

@mastra/mongodb@1.20.1

Patch Changes

  • Fixed documentFilter with operators like $regex failing on MongoDB Atlas vector queries. Filters that $vectorSearch can't evaluate now run as a pre-filter instead of being sent inside $vectorSearch.filter. (#25647)

@mastra/mysql@0.11.1

Patch Changes

  • Fixed putMany on the MySQL blob store overwriting existing blobs. Blobs whose hash is already stored are now skipped, matching put and the other storage adapters, so a blob keeps the createdAt of when it was first stored instead of being moved forward on every skill republish. (#25543)

@mastra/observability@1.18.3

Patch Changes

  • Fixed missing cost estimates for the newest models, such as OpenAI gpt-6-luna and gpt-6-sol, and Anthropic claude-opus-5-5 and claude-sonnet-5-5. The pricing data is now up to date. (#25559)

  • Fixed recorded traces choosing the wrong root span when a storage backend returns spans out of start order (for example ClickHouse or DuckDB) and the trace contains a span whose parent was never persisted. Scores and feedback added to these traces now carry the real root's entity and tags. (#25536)

  • Fixed provider API errors on traces showing only a message like "Service Unavailable". Span errors now include the HTTP status code, request URL, retryability and provider response body under details, so you can see what failed and where. (#25407)

@mastra/pg@1.28.1

Patch Changes

  • Fixed Postgres skill updates not advancing updatedAt when the update only re-sends unchanged skill content. Postgres now bumps updatedAt on every update, matching the in-memory and LibSQL stores, so PATCH responses and updatedAt-sorted skill lists stay consistent across stores. (#25537)

  • Fixed PgVector.query() with a filter only and includeVector: true on bit and sparsevec indexes. It threw a SyntaxError or returned a single number; it now returns the stored embedding as a number[], the same as vector-similarity queries. (#25561)

  • Fixed Postgres workflow definitions returning their creation time as updatedAt after an edit. (#25658)

  • Fixed Postgres workspace updates not advancing updatedAt when the update only re-sends unchanged workspace configuration. Postgres now bumps updatedAt on every update, matching the in-memory and LibSQL stores. (#25539)

@mastra/playground-ui@60.1.0

Minor Changes

  • Added SegmentedControl, a pill-shaped control for picking one of a few options. The selected option is marked by a thumb that slides between segments. Items can hold text, an icon and text, or only an icon (iconOnly). It supports the sm/md/lg control sizes, and disabled options with an optional tooltip. (#25570)

    import { SegmentedControl, SegmentedControlItem } from '@mastra/playground-ui/components/SegmentedControl';
    
    <SegmentedControl aria-label="Permission" value={policy} onValueChange={setPolicy}>
      <SegmentedControlItem value="allow">Allow</SegmentedControlItem>
      <SegmentedControlItem value="ask">Ask</SegmentedControlItem>
      <SegmentedControlItem value="deny">Deny</SegmentedControlItem>
    </SegmentedControl>;

    ThemeToggle is now built on SegmentedControl, so both look the same. It uses the shared control sizes, so the default size is slightly taller and lines up with buttons and selects. size="xs" is deprecated and renders as sm. Keyboard focus is now visible.

  • Improved warning and error colors so alerts, status dots, badges, buttons, charts, and usage values read as one family in light and dark mode. (#25587)

    • The yellow ramp is now amber. It warms as it darkens, so warnings read as gold instead of mustard or olive.
    • Red uses one hue across every step, so error text, badges, charts, and destructive buttons match.
    • Added --warning-foreground and --destructive-foreground for colored text and icons. *-indicator is the fill for dots, bars, chart marks, and borders. The warning fill is too light to read as text in light mode, so text needs its own token.
    • Dark-mode red surfaces (alerts, red badges, error washes) use a clear red instead of a brownish maroon, with a softer border.
    • Destructive and warning badges use the same text color as the values beside them.
    • Badge fills are translucent tints, so a badge follows the card or row under it on hover instead of sitting on it as a solid patch. On a resting surface they look the same as before. Product avatars stay solid.
    • The disabled destructive button uses a softer fill with muted text, so it no longer looks like an enabled button in a darker red.

    Removed

    Removed Replacement
    --yellow-50 … --yellow-950 and *-yellow-* utilities --amber-*, *-amber-*
    --yellow-soft-* and *-yellow-soft-* utilities --amber-soft-*, *-amber-soft-*
    --badge-yellow-strong, -subtle, -edge, -indicator, -foreground --badge-amber-*
    --chart-yellow --chart-amber
    Badge variant="yellow" variant="amber"
    'yellow' in categoricalHues and CategoricalHue 'amber'
    yellow-*, yellow-soft-*, badge-yellow-*, and chart-yellow keys in Colors from @mastra/playground-ui/tokens The matching amber keys
    text-warning-indicator and text-destructive-indicator for text and icons (the tokens remain for fills) text-warning-foreground, text-destructive-foreground

    --color-brand-yellow is part of the fixed Mastra palette and is unchanged.

    // Before
    <Badge variant="yellow">Pinned</Badge>
    <span className="text-warning-indicator">870K</span>
    <i className="bg-badge-yellow-indicator" />
    
    // After
    <Badge variant="amber">Pinned</Badge>
    <span className="text-warning-foreground">870K</span>
    <i className="bg-badge-amber-indicator" />

Patch Changes

  • Fixed pasting a single KEY=value line into an environment variable value field importing it as a new row instead of keeping it as the value. (#25640)

  • Fixed the thread view of a trace: resumed runs no longer show an empty user message, and long tool calls no longer cause horizontal scrolling. (#25586)

  • Removed the "Primitive ID" filter from the metrics dashboard. The metrics API ignored it, so the filter looked active but had no effect. (#25627)

  • Fixed the Studio trace thread view showing observational memory's internal output (such as the observer's capture JSON) as the agent's reply. Observational memory processor runs and their observer/reflector agents are now left out of the reconstructed conversation. (#25565)

  • The trace thread view no longer shows empty rows for task and working-memory tool calls, which the chat already hides. (#25565)

  • Fixed system messages in trace previews showing raw markdown (like # and **). They are now rendered as formatted text, like user and assistant messages. Long span input and output boxes (Preview and JSON) are now collapsed with an Expand button instead of scrolling inside a fixed height. (#25571)

    Added CollapsibleBox and useCollapsibleBox: a box that clips content past a measured height with a fade, while you place the expand control anywhere. The Plan component now uses it.

  • Thread view now only lists traces from the selected thread when trace query is disabled. (#25593)

  • The "Highlight spans" action for tool calls in the trace thread view now sits on the same line as the tool call instead of below it. (#25593)

  • Fixed variable autocomplete in the code editor leaving leftover text and duplicate closing braces when a suggestion was picked inside an existing {{placeholder}}. (#25638)

@mastra/qdrant@1.1.4

Patch Changes

  • Fixed QdrantVector.deleteVectors reporting success when Qdrant rejected the request. IDs that are not unsigned integers or UUIDs now throw a clear error instead of silently deleting nothing. (#25529)

@mastra/rag@2.6.6

Patch Changes

  • Generate document identifiers with Web Crypto (#25462)

@mastra/react@1.7.1

Patch Changes

  • Fixed Studio agent chat crashing with "Cannot read properties of undefined" when reopening a thread whose finished workflow tool call is replayed from the stream cache. Workflow chunks replayed onto a completed tool result now rebuild the workflow view instead of throwing. (#25497)

  • useChat now handles tool-call-resumed chunks. It clears the matching suspended tool or pending approval, and isAwaitingToolApproval becomes false once no paused tool calls remain in the resumed run. (#25491)

    const { isAwaitingToolApproval } = useChat({ agentId, threadId, resourceId });
    
    return isAwaitingToolApproval ? <ApprovalPrompt /> : null;

@mastra/schema-compat@1.3.13

Patch Changes

  • Fixed OpenAI strict-mode schema preparation rejecting allOf object schemas with properties named constructor, toString, or __proto__. (#25655)

@mastra/server@1.73.0

Patch Changes

  • Fixed durable agent resume, approve, and decline routes returning 403 to the run's own caller when no auth middleware sets a server-side identity. Requests without an identity are now treated like workflow run ownership checks treat them, while requests with an identity are still checked against the run's resource and thread. Fixes #25511. (#25556)

  • Fixed durable agent resume and tool approval routes returning 403 ("belongs to a different resource" or "tool call is not suspended") when the client resumes immediately after receiving a tool approval event. The access check now waits briefly for the suspended run to be saved before denying the request. (#25611)

  • Use Web Crypto for server-generated IDs and compatible A2A agent-card signatures while preserving legacy PEM key support. (#25462)

  • Fixed Studio showing the wrong provider for durable or dynamic agents that use a gateway model. An agent on mastra/openai/gpt-5-mini now shows the Mastra gateway instead of OpenAI, so Studio no longer asks for OPENAI_API_KEY when MASTRA_GATEWAY_API_KEY is set. (#25620)

  • Fixed A2A tasks/list returning the full message history when historyLength is 0. It now returns no history, as requested. (#25607)

@mastra/slack@1.7.1

Patch Changes

  • Fixed the Slack provider reporting config drift and re-pushing the app manifest on the first restart after every install that uses slash commands. (#25625)

@mastra/telegram@0.2.1

Patch Changes

  • Fixed polling mode allowing the same Telegram bot to be connected to more than one agent. The second connect() now fails with the same "already connected" error as webhook mode, instead of starting a second poll loop that conflicts with the first. (#25645)

@mastra/upstash@1.5.1

Patch Changes

  • Fixed Upstash Vector filters so { field: { $not: { $nin: [...] } } } translates to field IN (...) instead of an invalid inequality. (#25614)

Other updated packages

The following packages were updated with dependency changes only: