Skip to content

July 27, 2026

Latest

Choose a tag to compare

@PaulieScanlon PaulieScanlon released this 29 Jul 08:33
0dca9d0

Highlights

Read-only local sandbox & filesystem support

New readOnly options on LocalFilesystem and NativeSandboxConfig let you run local sandboxes with a read-only working directory on macOS (Seatbelt) and Linux (Bubblewrap) for safer execution.

Custom thread ID resolution for channels

ChannelConfig.resolveThreadId lets hosts control the internal Mastra thread id for newly created channel threads (after resolveResourceId), enabling clean alignment with external IDs like session IDs.

Explicit channel reaction tools (less implicit agent tool injection)

Channel reaction tools (add_reaction, remove_reaction) are no longer auto-injected into channel-bearing agents; if you want reactions, you now opt in by adding channels.getTools().

Stored agent versioning: auto-publish on update

@mastra/client-js adds autoPublish to stored agent updates so you can immediately activate a newly created agent version as part of the update call.

Reliability & concurrency improvements across Factory + stores

Factory work-item processing now uses atomic claims/idempotent replay (replacing distributed advisory locks), and @mastra/libsql fixes concurrent-write data loss/corruption in observational memory by serializing updates; composite-store “disabled domain” observability/score endpoints now return clear 501 responses instead of 500s.

Breaking Changes

  • Channel reaction tools (add_reaction, remove_reaction) are no longer automatically injected into a channel-bearing agent’s toolset; add them explicitly if needed.

Changelog

@mastra/core@1.53.0

Minor Changes

  • Added a readOnly option to NativeSandboxConfig to restrict the local sandbox's working directory to read-only access on macOS (Seatbelt) and Linux (Bubblewrap). (#18999)

    Usage Example:

    import { Workspace, LocalFilesystem, LocalSandbox } from '@mastra/core';
    
    const workspace = new Workspace({
      filesystem: new LocalFilesystem({ basePath: './workspace', readOnly: true }),
      sandbox: new LocalSandbox({
        workingDirectory: './workspace',
        isolation: 'bwrap', // or 'seatbelt'
        nativeSandbox: {
          readOnly: true,
        },
      }),
    });
  • Added resolveThreadId to ChannelConfig: resolve the internal Mastra thread id before a channel thread is created, mirroring resolveResourceId. The hook runs after resolveResourceId (the resolved owner is on the context) and only for newly-created threads — existing threads keep their stored id. This lets a host align channel thread ids with ids it controls, e.g. give the thread the same id as the session it belongs to: (#20147)

    const channels = new AgentChannels({
      adapters,
      resolveResourceId: async ctx => resolveSessionId(ctx),
      resolveThreadId: ({ resourceId, defaultThreadId }) => (isSessionId(resourceId) ? resourceId : defaultThreadId),
    });
  • Channel reaction tools (add_reaction, remove_reaction) are no longer injected into a channel-bearing agent's toolset automatically. Replies are unaffected — they stream back to the channel without a tool. If you want your agent to react to channel messages, add the tools explicitly: (#20152)

    const channels = new AgentChannels({
      adapters: { slack: createSlackAdapter() },
    });
    
    const agent = new Agent({
      name: 'assistant',
      model: 'openai/gpt-5',
      channels,
      tools: { ...channels.getTools() },
    });

Patch Changes

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

  • Fixed sub-agent tool approvals resuming the wrong run. When a sub-agent suspends for approval and the bot restarts, the approval handler now correctly resumes the parent agent's run instead of the sub-agent's. (#19769)

  • Removed redundant non-null assertions from core control flow. (#20140)

  • Fixed thread title generation receiving each conversation message twice. The duplicated transcript confused small title models into replying to the conversation instead of producing a title, so threads could get refusal text as their title. (#20141)

  • Improved Factory work-item concurrency by replacing distributed advisory locks with atomic claims, idempotent replay, and serializable relationship transactions. (#20135)

  • Keep deprecated provider models in the model registry instead of dropping them (#20220)

    The models.dev gateway filtered out every model marked status: 'deprecated' upstream. That status means "still served, scheduled for retirement" rather than "removed", so filtering it silently degraded models that still work.

    A dropped model lost its capability data: modelSupportsAttachments, modelSupportsTemperature, and modelSupportsStructuredOutput return false for a model that is missing from a known provider's capability file, rather than undefined. A model that genuinely supports attachments therefore reported that it does not. Dropped models also lost their per-model endpoint/shape/SDK overrides, so a model that needs a non-default endpoint or SDK routed with provider defaults instead. They also disappeared from the generated model-id union used for editor autocomplete, and from any surface that lists a provider's models.

    Deprecated models are now retained in models, in the generated types, and in the capability and override data. They are additionally reported through a new optional deprecatedModels field on ProviderConfig, so surfaces that offer models for new selection can hide or mark them.

  • Fixed isTaskComplete completion checks leaking the internal scorer report (#### Completion Check Results) into the agent's final answer and saved conversation history. (#19951)

    When completion scorers passed on the first check, the report was appended after the model's answer and became the last response message. Agents with memory (or any output processors) then resolved stream.text and the persisted assistant message to the report instead of the real answer.

    const stream = await agent.stream('What is the capital of France?', {
      memory: { thread, resource },
      isTaskComplete: { scorers: [myScorer] },
    });
    
    // Before: '#### Completion Check Results ...'
    // After:  'The capital of France is Paris.'
    console.log(await stream.text);

    Scorer feedback is now only added to the conversation when a check fails, where it steers the next iteration. Failing checks still retry with feedback exactly as before. Fixes #19875.

  • Fixed AI SDK v7 providers receiving screenshot and file tool results in an older content format. Tool result media is now sent in the file content shape expected by v7 providers such as Bedrock. (#19755)

@mastra/client-js@1.34.0

Minor Changes

  • Added autoPublish to stored agent updates so callers can activate a newly created version immediately. (#19794)

    await client.getStoredAgent('agent-id').update({
      instructions: 'Updated instructions',
      autoPublish: true,
    });

Patch Changes

  • Improved generated route type formatting. (#19807)

@mastra/code-sdk@1.0.2

Patch Changes

  • Fixed stored provider API keys so authenticated models appear as configured and continue working during steering and follow-up messages. (#20143)

  • Added a 15s AbortSignal timeout to the Anthropic OAuth token-exchange and refresh fetches so an unresponsive upstream cannot pin the caller indefinitely. (#20129)

@mastra/factory@0.2.1

Patch Changes

  • Removed Git and GitHub route locking that held database transactions open during sandbox and network operations. (#20135)

  • Improved Platform GitHub event polling efficiency and added event-count and latency logging for each poll. (#20123)

  • Bound the withProjectLock / withDbAdvisoryLock critical section with an AbortSignal timeout (default 60s, configurable via timeoutMs). Previously, an unbounded outbound call inside the lock could keep the transaction open for up to Neon's idle_in_transaction_session_timeout (5 minutes), pinning the pool connection and the advisory lock the entire time. On timeout the wrapper aborts the fn's signal, rolls the transaction back, releases the connection, and throws ProjectLockTimeoutError. (#20129)

  • Improved Factory work-item concurrency by replacing distributed advisory locks with atomic claims, idempotent replay, and serializable relationship transactions. (#20135)

  • Fixed the workspace files panel in Factory web returning "Path is outside the browsable root" for Factory sessions. The workspace file endpoints now recognize a session id, reattach to that session's sandbox, and list and read rendered files (like .artifacts) directly from the sandbox, so session artifacts render on deployed factories. (#20101)

  • Added an updateIssue capability to the Intake surface so Factory can change the state of external issues (open/closed on GitHub, workflow state on Linear) as a side effect of stage transitions. Adapters cover the direct GitHub, direct Linear, platform GitHub, and platform Linear integrations. GitHub adapters reject pull-request targets. Linear adapters resolve the target workflow state per team and skip when the issue is already in the desired state. The platform Linear adapter degrades to a no-op (returns null) when the platform workflow-states endpoint is not yet deployed, so this change is safe to ship ahead of the platform companion route. This is a plumbing change: no rule currently emits the new decision, so behavior is unchanged. (#20111)

  • Fixed Factory integrations so GitHub and Linear attach their own event rules. This restores work-item rule ingestion for Platform-backed Linear intake and for the Platform GitHub issue poller. (#20169)

@mastra/libsql@1.17.1

Patch Changes

  • Fixed data loss and corruption in observational memory when it is written to concurrently on a local SQLite database. Buffered observations could previously be dropped or leave the memory record in an inconsistent state under load; memory updates are now serialized so concurrent writes are preserved. (#20110)

  • Fixed local LibSQL stores changing shared database journal state when they close. (#20227)

@mastra/pg@1.17.1

Patch Changes

  • Improved Factory work-item concurrency by replacing distributed advisory locks with atomic claims, idempotent replay, and serializable relationship transactions. (#20135)

  • Hardened distributed lock cleanup so clients are destroyed when transaction rollback fails. (#20135)

@mastra/platform-workspace@0.2.1

Patch Changes

  • Fixed PlatformSandbox reattach so stale sandbox IDs are recreated before commands run. (#20102)

@mastra/playground-ui@43.0.0

Patch Changes

  • Fixed autoscroll scrollbars not becoming transparent. (#20171)

  • Fixed Studio repeatedly polling observability endpoints when the observability storage domain is disabled. Studio now treats the disabled domain as an unavailable capability: score and log views stop polling, failed requests are not retried, and the Logs page shows a clear unavailable state instead of a generic error. Related to #20157. (#20158)

  • Fixed the trace feedback panel continuing to poll every 3 seconds when the observability storage domain is disabled. Studio now also recognizes the "Scores storage domain is not available" response from the span scores endpoint, so span score polling stops for disabled scores storage as well. Follow-up to #20158. (#20170)

@mastra/server@1.53.0

Patch Changes

  • Fix Studio's provider connection banner incorrectly showing Google and Vertex AI as disconnected. (#19816)

    • Google now connects with either GOOGLE_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY, not both.
    • Vertex AI is now checked separately from Google AI Studio, using its own GOOGLE_VERTEX_PROJECT and GOOGLE_VERTEX_LOCATION settings.
  • Fixed stored agent draft saves to preserve the published version unless automatic publication is requested. (#19794)

  • Fixed the span scores endpoint returning HTTP 500 when the scores storage domain is disabled (e.g. domains: { scores: false } on a composite store). The server now responds with HTTP 501 Not Implemented and a clear message, matching how the disabled observability domain is reported. Follow-up to #20158. (#20170)

  • Fixed observability endpoints returning HTTP 500 when the observability storage domain is disabled (e.g. domains: { observability: false } on a composite store). The server now responds with HTTP 501 Not Implemented and a clear message — consistent with how other capability gaps (delta polling, workspace v1) are reported — so an intentionally disabled capability is no longer reported as an internal server failure. Fixes #20157. (#20158)

@mastra/voyageai@0.4.0

Minor Changes

  • Fixed VoyageAI multimodal embeddings sending text as bare strings (the API rejected the payload) and added a baseUrl option so you can point the embedder, reranker, and contextualized models at a provider-hosted Voyage endpoint. (#19804)

    Before

    // multimodal text was serialized as inputs: [["text"]] -> HTTP 400

    After

    const embedder = voyage.multimodalEmbedding({
      model: 'voyage-multimodal-3.5',
      baseUrl: 'https://ai.mongodb.com/v1',
    });

Other updated packages

The following packages were updated with dependency changes only: