releases.shpreview

V8-isolated Code Mode; provider-native web search; ChannelHandler requires 4th arg

@mastra/core@1.55.0

4 features3 enhancements7 fixesThis release4 featuresNew capabilities3 enhancementsImprovements to existing features7 fixesBug fixesAI-tallied from the release notes
From the original release noteView original ↗

Highlights

In-process Code Mode execution (no workspace sandbox required)

Code Mode transports can now declare requiresSandbox: false, letting createCodeMode() run without a workspace sandbox for in-process execution boundaries. This enables secure in-process runtimes like V8 isolates and exports sanitizeToolId so transports can share consistent external_* naming.

New @mastra/isolated-vm package for V8-isolated Code Mode

Introduces @mastra/isolated-vm with IsolatedVmCodeModeTransport, running model-authored programs inside an in-process V8 isolate with no filesystem/network/process access (only bridged external_* tools). Note: requires isolated-vm native addon and Node 20+ hosts must start with --no-node-snapshot.

Built-in provider-native Web Search tool

@mastra/core adds webSearchTool, a first-party web search tool that resolves to provider-native search when supported by the configured model/provider, simplifying “current info” agent setups.

Stored agent drafts via autoPublish (Server + JS SDK)

Both @mastra/server and @mastra/client-js add autoPublish to stored agent creation so you can create an initial unpublished draft for review before publishing (existing calls still publish immediately by default).

New Factory channel identity domain + channels integration slot

@mastra/factory adds a channel-identity storage domain to link chat-platform senders to Factory users, plus a channels() integration slot to attach an AgentControllerChannels during prepare() so inbound platform messages can drive the same agents as the web UI.

Breaking Changes

  • ChannelHandler context parameter is now required: the 4th parameter is ctx: ChannelHandlerContext (non-optional). Code that calls a ChannelHandler-typed function with only three args must be updated to pass ctx.

Changelog

@mastra/core@1.55.0

Minor Changes
  • Added support for Code Mode transports that provide their own execution boundary. A transport can now declare requiresSandbox: false and createCodeMode() will run it without a workspace sandbox, which enables in-process transports such as IsolatedVmCodeModeTransport from @mastra/isolated-vm: (#20359)

    import { createCodeMode } from '@mastra/core/tools';
    import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';
    
    // No sandbox needed — the V8 isolate is the execution boundary
    const { tool, instructions } = createCodeMode({ tools }, new IsolatedVmCodeModeTransport());

    Also fixed the generated Code Mode instructions to describe isolation accurately instead of always claiming the program runs fully sandboxed, since the actual boundary depends on the configured sandbox and transport. The sanitizeToolId helper used for external_* naming is now exported from @mastra/core/tools so transports can reuse it instead of duplicating it.

  • Added retry callbacks for stream error policies and ensured explicit matcher policies override provider retry metadata. (#19724)

  • Channel handlers can now contribute to the request context of the run they start. (#20060)

    ChannelHandlerContext gains a requestContext field holding the RequestContext for the run the inbound message is about to start. It is constructed fresh for every message, and a handler may write to it before calling defaultHandler. Core then adds its own channel and render-context entries and dispatches with the same instance, so anything the handler wrote reaches the run.

    import { AgentControllerChannels } from '@mastra/core/channels';
    
    const channels = new AgentControllerChannels({
      adapters,
      handlers: {
        onDirectMessage: async (thread, message, defaultHandler, ctx) => {
          ctx.requestContext.set('locale', 'en-GB');
          await defaultHandler(thread, message);
        },
      },
    });

    Anything a run reads from its request context can now be decided per inbound message — for example resolving which user a platform sender maps to, so the run uses that user's stored credentials.

    Contract change: ChannelHandler's 4th ctx parameter is now non-optional (ctx: ChannelHandlerContext, previously ctx?: ChannelHandlerContext). Core has always passed it, and requiring it means a handler writing ctx.requestContext.set(...) needs neither a non-null assertion nor a guard that would silently skip the write.

    Handler implementations are unaffected: TypeScript lets a function declaring fewer parameters satisfy a type declaring more, so existing three-parameter handlers — and anyone who wrote ctx?.mastra — keep compiling. Code that calls a ChannelHandler-typed value with three arguments does need updating, and will fail with Expected 4 arguments, but got 3 until the context is passed.

  • Added a built-in web search tool that resolves to provider-native search for supported models. (#20345)

    import { Agent } from '@mastra/core/agent';
    import { webSearchTool } from '@mastra/core/tools';
    
    export const agent = new Agent({
      name: 'web-search-agent',
      instructions: 'Use web search for current information.',
      model: 'openai/gpt-5-mini',
      tools: { webSearch: webSearchTool },
    });
Patch Changes
  • Update provider registry and model documentation with latest models and providers (3f472b4)

  • Fixed Zod 4 installations reporting peer dependency warnings. (#20313)

  • Fixed channel tool approval actions so missing thread mappings cannot create conversations under the button clicker's identity. (#20374)

  • Fixed duplicate delegation prompts in sub-agent threads. When a supervisor agent delegated to a sub-agent without its own memory and a memory processor persisted messages during the run (such as observational memory), the delegation prompt was saved twice to the sub-agent's thread (once by the mid-run persistence and once by the delegation transcript save). The prompt now keeps a stable message ID across both writes so it is persisted exactly once. Delegation prompt rows are now stored with the default v2 message type instead of text, consistent with other persisted messages. (#20174)

  • Review sessions now load project AGENTS.md/CLAUDE.md from the pull request's trusted base branch instead of skipping them entirely. The working-tree copies on an untrusted checkout remain excluded from the system prompt and reminder injection; content is served from the base ref via git, and sessions without a known base ref still skip project instruction files. (#20372)

  • Improved workflow and MCP tool-result formatting to avoid serializing large values during equality checks while preserving explicit model outputs. (#20340)

  • Review sessions no longer ingest AGENTS.md or CLAUDE.md from the checked-out pull request branch. A PR branch is third-party content, so its instruction files are treated as content under review instead of trusted configuration — closing a prompt-injection path into the reviewer agent. The reviewer also runs the PR's install/build/test commands with GitHub tokens stripped from the environment. (#20372)

  • Added an option to the instruction-file reminder processor that lets hosts disable injection entirely for a request, so instruction files from untrusted checkouts are never surfaced as reminders. (#20372)

  • Fixed the default workflow execution engine serializing the full RequestContext on every step and entry and then discarding the result. serializeRequestContext probes every stored value with JSON.stringify via RequestContext.toJSON(), but on the default engine the serialized object was never read — only engines with requiresDurableContextSerialization() (e.g. Inngest) restore context from serialized results. The step/entry return paths now skip serialization on the default engine; snapshot persistence is unaffected. (#20369)

@mastra/client-js@1.36.0

Minor Changes
  • Added the autoPublish option to createStoredAgent() so SDK users can create an unpublished initial draft. (#20381)

    await mastraClient.createStoredAgent({
      id: 'support-agent',
      name: 'Support agent',
      instructions: 'Help customers with support questions.',
      model: { provider: 'openai', name: 'gpt-5' },
      autoPublish: false,
    });
Patch Changes
  • Added TraceInsightResponse for typed entity-learning trace summaries. (#20405)

    import type { TraceInsightResponse } from '@mastra/client-js';
    
    const traceId = (insight: TraceInsightResponse) => insight.traceId;
  • Added Trace Intelligence progress types and improved the onboarding state with processing progress, clearer copy, accessible markup, mobile polish, and the dedicated documentation link. (#20401)

@mastra/code-sdk@1.1.1

Patch Changes
  • Extended Mastra Code's transient retry policy to cover provider server errors with up to 10 retries and exponential backoff starting at 500ms. (#20393)

  • Improved Mastra Code connection recovery with up to 10 retries, exponential backoff starting at 500ms, and visible retry progress in the TUI. (#19724)

  • Fixed the OpenAI pack to use its supported default model ID. (#20423)

  • Review sessions now load project AGENTS.md/CLAUDE.md from the pull request's trusted base branch instead of skipping them entirely. The working-tree copies on an untrusted checkout remain excluded from the system prompt and reminder injection; content is served from the base ref via git, and sessions without a known base ref still skip project instruction files. (#20372)

  • Fixed sandbox file tools (view, write, edit, list) failing with "Path not found" in Factory sessions when called with absolute paths inside the session working directory. File tools now also work on macOS-hosted local sandboxes, not just Linux VMs. (#20325)

  • Sandbox filesystem operations now behave like local ones: missing files, existing destinations, and directory misuse raise typed errors instead of generic ones, reading a directory as a file fails instead of returning empty content, moving or copying a file into a new directory works, overwrite protection can no longer be raced by concurrent writers, and each filesystem reports a unique id and status. (#20325)

  • Review sessions no longer ingest AGENTS.md or CLAUDE.md from the checked-out pull request branch. A PR branch is third-party content, so its instruction files are treated as content under review instead of trusted configuration — closing a prompt-injection path into the reviewer agent. The reviewer also runs the PR's install/build/test commands with GitHub tokens stripped from the environment. (#20372)

  • Added an option to the instruction-file reminder processor that lets hosts disable injection entirely for a request, so instruction files from untrusted checkouts are never surfaced as reminders. (#20372)

@mastra/deployer-sandbox@0.2.0

Minor Changes
  • Run isolated non-HTTP workers with bounded input, separate byte-preserving output streams, cancellation, relaunch, and cleanup controls. (#19641)

    import { deployWorkerToSandbox } from '@mastra/deployer-sandbox';
    
    const worker = await deployWorkerToSandbox({
      sandbox,
      dir: './dist/worker',
      executionId: 'job-1',
      command: 'node',
      args: ['index.mjs'],
      input: { type: 'stdin', data: request },
    });
    
    const stdout = await worker.readOutput('stdout');
    await worker.cancel();
    const retry = await worker.relaunch({ executionId: 'job-2' });
    await retry.destroy();

@mastra/e2b@0.8.0

Minor Changes
  • Raised the @mastra/core peer dependency floor to >=1.55.0-0. The previous floor (>=1.12.0-0) was stale: E2BCodeModeTransport already relies on Code Mode runtime exports that only exist in much newer cores, so older pairings crashed at import time. E2BCodeModeTransport now also reuses the sanitizeToolId helper exported from @mastra/core/tools for external_* naming instead of a local copy, guaranteeing it stays identical to the names in the generated stubs. (#20359)

@mastra/factory@0.3.0

Minor Changes
  • Added a channel-identity storage domain so a factory can link a chat-platform sender to one of its own users, and a channels() slot so an integration can supply the chat platform itself. (#20060)

    ChannelIdentityStorage persists account links keyed by platform, external team id, and external user id, and records an optional default factory project per link. A link is written only after the chat platform itself asserts the account through OpenID Connect, with the existing createStateSigner binding the round trip to the tenant that started it.

    FactoryIntegration gains an optional channels(ctx) returning an AgentControllerChannels, which the factory attaches to the mounted agent controller during prepare(). Inbound platform messages then reach the same agents the web UI drives, without the deploy entry reaching into the prepared controller to wire them by hand. IntegrationContext gains storage.channelIdentity for integrations that use the slot. Providing channels() adds the channel-identity domain to the integration's readiness requirements, so an integration whose reverse index is not migrated reports not-ready and its channels never attach. Only one integration may provide channels; a second fails the boot, because attaching replaces rather than merges.

    StateTenant — what StateSigner.verify returns — gains a nonce field carrying the per-state random value. A signed state stays valid for its whole lifetime, so a flow that must not run twice off one state can key single-use bookkeeping on the nonce; the Slack account-link callback burns it before spending the authorization code. verify now rejects a state carrying no nonce.

    The integration seam itself — FactoryIntegration, IntegrationContext, IntegrationHooks, and IntegrationTools — is now exported from the package entry point. Implementing an integration outside this package was already the documented path for third parties, but the types to do it were unreachable. ChannelIdentityStorage and createFactoryRouteAuth are exported too, alongside the existing projects and work-items storage domains.

    Fixed sign-in returning to the root path instead of the page the visitor started from. The OAuth state carrying that destination was encoded as Base64URL JSON, but MastraAuthStudio reads the uuid|encodedPath shape, so it never found a destination and every sign-in landed on /. The state now uses that shape, and the destination is also stashed in a short-lived HttpOnly cookie for providers that do not echo state back to the callback.

  • Added a per-Factory Slack work-item setting so a new Slack thread only opens a Work-board card when that Factory opts in, and Slack OAuth now returns to the Factory the flow started from. (#20395)

Patch Changes
  • Fixed workspace re-opening failing when the session's agent switched branches and left uncommitted work in the tree. The workspace now keeps the checkout on its current branch instead of returning an error — the session's work in progress always wins over the recorded branch. (#20372)

  • Move Github log to debug instead of info in factory (#20331)

  • Opening a workspace no longer fails when the repository checkout holds uncommitted or untracked files that block git pull (for example residue from a changeset-version run or a build). Materialization now keeps the checkout as-is — the same treatment diverged session branches already receive — instead of surfacing "git pull failed: Your local changes would be overwritten by merge" and refusing to open the thread. Local state is never discarded to force the pull through. (#20372)

  • Stop long-running Factory dispatches from starving the decision queue. The dispatcher poll loop previously awaited every dispatch to completion before claiming again, so a single slow effect (a skill kickoff consuming a full agent run, or binding preparation cloning a repository) froze the whole queue and left every other rule effect stuck in "pending" — sometimes for the 15-minute sandbox clone timeout times five retry attempts. Dispatches now run detached from the poll loop under a bounded in-flight cap while lease renewal keeps them protected from re-claim, so new decisions keep flowing while slow ones finish. (#20356)

  • Added model switching to Factory review sessions so work can continue during a model outage. (#20423)

  • Fixed a boot-time provisioning storm where several concurrent requests for the same cold session (for example multiple open browser tabs polling right after a server restart) each provisioned their own sandbox. Concurrent sandbox opens for the same session now share one in-flight provision, so only a single sandbox is created per session. (#20380)

  • Fixed manual issue triage in platform deployments. The triage runner is now automatically derived from the mounted controller, so manual triage no longer returns 503 when no explicit runner is configured. The manual triage endpoint now shares the same wrapper as webhook-triggered triage, ensuring labels and default model resolution are handled consistently. (#20362)

  • Improved contributor guidance for Factory backend development. (#20327)

  • Fixed Factory losing repository access after a GitHub App is reinstalled with a new installation ID. (#20348)

  • Review sessions now load project AGENTS.md/CLAUDE.md from the pull request's trusted base branch instead of skipping them entirely. The working-tree copies on an untrusted checkout remain excluded from the system prompt and reminder injection; content is served from the base ref via git, and sessions without a known base ref still skip project instruction files. (#20372)

  • Factory review verdicts are stricter and grounded in the full review record: (#20372)

    • The reviewer waits for pending review bots to finish on the head commit (polling up to 10 minutes) before forming a verdict, then reads existing reviews — bot and human — and every substantive prior finding is confirmed, addressed, or refuted with evidence. Confirmed unaddressed major findings block approval.
    • Approval is earned through explicit gates: verification executed, all prior findings dispositioned, no bot still pending, behavior covered by tests, adversarial self-check survived. Any concrete change the author should make before merge means "request changes", borderline calls tie-break toward "request changes", and real defects can't be relabeled non-blocking to protect an approval.
    • Non-blocking findings with mechanical fixes ship as a follow-up PR opened by the reviewer against the reviewed PR's branch, instead of landing as homework for the author.
    • The reviewer is hardened against prompt injection: PR content can never direct the review, steering attempts become blocking security findings, bot identity is verified by account login, the PR's install/test-time code is inspected before anything is executed, and follow-up PRs only ever contain code the reviewer authored.
    • The reviewer runs the changed packages' tests and typecheck itself instead of trusting green CI, and every approval must survive an adversarial self-check.
    • PRs with merge conflicts still get a full review but are never approved and never have their conflicts resolved by the reviewer.

    Reviews arrive on the pull request itself, published via gh pr review --approve or gh pr review --request-changes before the review pass completes.

  • Fix Factory workspaces not being available to HTTP routes immediately after creation. Sessions now consistently reuse the same workspace across requests. (#20421)

  • Fixed Factory rules treating a work item from a non-GitHub, non-Linear source as a GitHub issue. A Slack thread card moved into Triage ran the GitHub issue rule and handed the triage agent a Slack permalink labeled as a GitHub issue; those cards now resolve the plain work-item rules instead. (#20395)

  • Review sessions no longer ingest AGENTS.md or CLAUDE.md from the checked-out pull request branch. A PR branch is third-party content, so its instruction files are treated as content under review instead of trusted configuration — closing a prompt-injection path into the reviewer agent. The reviewer also runs the PR's install/build/test commands with GitHub tokens stripped from the environment. (#20372)

  • Fixed Factory provisioning a fresh Platform sandbox for every new session. When a work item finishes or a session is deleted, its sandbox is scrubbed back to the repository's default branch (including gitignored files) and returned to a per-repository reuse pool, so new sessions for the same repository reuse a pooled sandbox instead of spinning up another VM. (#20328)

    GitHub tokens are injected per command and are no longer stored in the sandbox environment, so a reused sandbox never carries a previous session's credentials.

  • Added an option to the instruction-file reminder processor that lets hosts disable injection entirely for a request, so instruction files from untrusted checkouts are never surfaced as reminders. (#20372)

@mastra/isolated-vm@0.1.0

Minor Changes
  • Added @mastra/isolated-vm, a new package with IsolatedVmCodeModeTransport — a Code Mode transport that runs model-authored programs in an in-process V8 isolate (backed by isolated-vm). The isolate is the execution boundary, so no workspace sandbox is required: the program has no filesystem, network, or process access, and its only capabilities are the external_* tool functions bridged back to the host. (#20359)

    import { createCodeMode } from '@mastra/core/tools';
    import { IsolatedVmCodeModeTransport } from '@mastra/isolated-vm';
    
    const { tool, instructions } = createCodeMode({ tools }, new IsolatedVmCodeModeTransport({ memoryLimitMb: 128 }));

    Note: isolated-vm is a native addon, and on Node.js 20+ the host process must be started with --no-node-snapshot (for example NODE_OPTIONS=--no-node-snapshot). See the docs for setup details. Resolves https://github.com/mastra-ai/mastra/issues/20329.

@mastra/platform-workspace@0.2.3

Patch Changes
  • Fix direct-exec fallback loop: when the WebSocket transport fails on a sandbox (Railway rejects the handshake, mid-stream drop, etc.), disable direct-exec permanently for that sandbox instead of re-minting a fresh lease on every subsequent exec. Also surface WebSocket close code, reason, and opened state in DirectExecResult and emit a diagnostic warning on transport failure so we can see why Railway is refusing the upgrade in production. (#20412)

@mastra/playground-ui@45.0.0

Patch Changes
  • Refreshed the HoverCard look: rounded corners, a soft elevation shadow, tighter padding, and the same white-in-light-mode surface as dropdowns and popovers. (#20365)

  • Fixed long unbreakable text in Notice, such as a git remote URL with an embedded token, spilling outside the notice box. Messages now wrap at any character and long titles truncate. (#20426)

  • Fixed the MainSidebar mobile menu button staying visible on desktop. Its hide rule used a zero-specificity selector, so an app stylesheet loaded after the design system's could win and leave the hamburger next to the desktop sidebar. (#20425)

  • Added Trace Intelligence progress types and improved the onboarding state with processing progress, clearer copy, accessible markup, mobile polish, and the dedicated documentation link. (#20401)

@mastra/server@1.55.0

Minor Changes
  • Added autoPublish to stored agent creation so callers can review an initial draft before publishing it. Existing calls continue to publish immediately. (#20381)

    await client.createStoredAgent({
      id: 'support-agent',
      name: 'Support agent',
      instructions: 'Help customers with support questions.',
      model: { provider: 'openai', name: 'gpt-5' },
      autoPublish: false,
    });

Other updated packages

The following packages were updated with dependency changes only:

Fetched July 31, 2026

V8-isolated Code Mode; provider-native web search;… — releases.sh