github mastra-ai/mastra @mastra/core@1.54.0
July 28, 2026

9 hours ago

Highlights

AgentController Chat Channels (Slack/Discord/Telegram, etc.)

AgentController can now run durable agent sessions inside chat threads via Chat SDK adapters, with native streaming output, tool approval cards, typing indicators, and controller-owned webhook routes at /api/agent-controllers/<CONTROLLER_ID>/channels/<PLATFORM>/webhook.

MongoDB Vector Store: Bring-Your-Own Collections + Hybrid (Vector + Full-text) Retrieval

MongoDBVector can now index existing operational collections (with safe, read-only-by-default semantics), return full source documents via metadataMode: 'document', and add full-text + hybrid retrieval via createSearchIndex, textQuery, and hybridQuery (Atlas Search / MongoDB 8.0+).

Exact Metadata Filtering Across Memory APIs and Storage Providers

Message history queries (memory.recall) now support exact-match metadata filtering with AND semantics, implemented across Memory APIs and supported backends (e.g. pg, mysql, mongodb, redis, clickhouse, cloudflare, dynamodb, spanner, etc.).

Smoother Streaming for Agents and AI SDK Routes

New smoothStream() plus experimental stream transforms buffer text/reasoning deltas into consistent chunks, and the AI SDK now supports the same smoothing via handleChatStream(), chatRoute(), and toAISdkStream().

Faster PlatformSandbox Exec via Direct WebSocket Data Plane

@mastra/platform-workspace adds a direct exec path that talks to Railway’s WebSocket endpoint using short-lived JWT leases, removing the workspace proxy from the exec hot path (lower latency for large commands like pnpm install) with automatic fallback to legacy proxy exec.

Breaking Changes

  • Channel handlers now receive a 4th argument: ChannelHandlerContext (use ctx.mastra to access the resolved Mastra instance).

Changelog

@mastra/core@1.54.0

Minor Changes

  • Channel handlers now receive a 4th argument: a ChannelHandlerContext carrying the resolved mastra instance. Custom handlers can read ctx.mastra. (#19289)

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

  • Added status-bearing judge execution details to scorer results. (#20022)

    const result = await scorer.run(input);
    const execution = result.judge?.generateScore?.executions[0];
    
    if (execution?.status === 'success') {
      console.log(execution.output, execution.usage);
    }

    Prompt-based scorer steps now expose successful logical executions with status: 'success', their prompt, structured output, judge model identity, normalized token usage, attempt and model-call counts, and duration. A structured-output fallback that eventually succeeds remains one execution with its attempts aggregated. Use this data to interpret one scorer run without reconstructing it from traces.

  • Added chat channel support to AgentController. Configure channels with Chat SDK adapters (Slack, Discord, Telegram, and more) to run a controller-backed agent session inside a messaging thread: each chat thread maps to one durable controller session, the agent's streamed output renders back to the platform with native streaming, tool approval cards, and typing status, and tool approvals resolve through the session's approval gate. (#19289)

    import { AgentController } from '@mastra/core/agent-controller';
    import { createSlackAdapter } from '@chat-adapter/slack';
    
    const agentController = new AgentController({
      id: 'my-agent-controller',
      agent,
      modes,
      channels: {
        adapters: {
          slack: createSlackAdapter(),
        },
      },
    });

    Registering the controller on a Mastra instance exposes a webhook route per adapter at /api/agent-controllers/<CONTROLLER_ID>/channels/<PLATFORM>/webhook. Adapters can be constructed manually here; provider-managed connect flows (such as Slack's controller-owned installations) are also supported. Controller channels need a long-lived server.

    Controller channels attach to the backing agent instance (via setChannels, propagated to every backing agent including per-mode agents) rather than being stamped onto each run's request context. Only agents explicitly given channels attach the channel output processor, so child runs such as observational-memory observers and forked subagents no longer render to the chat platform.

    Inbound channel messages routed into a controller session keep their platform metadata: the message's providerOptions (author name, user ID, message ID, and so on under mastra.channels.<PLATFORM>) are stamped onto the persisted user message as content.providerMetadata, matching the plain agent channel path.

  • Added a built-in web fetch tool export for agents to retrieve HTTP and HTTPS page content. (#20232)

    import { Agent } from '@mastra/core/agent';
    import { webFetchTool } from '@mastra/core/tools';
    
    export const agent = new Agent({
      name: 'Research agent',
      instructions: 'Use web_fetch when you need page content.',
      model,
      tools: { web_fetch: webFetchTool },
    });
  • Added smoothStream() and experimental agent stream transforms for buffering text and reasoning deltas into consistent, delayed chunks. (#19792)

    const stream = result.fullStream.pipeThrough(smoothStream());

Patch Changes

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

  • Fixed skill_read returning an empty string when startLine is past the end of a file, which left agents unable to tell end-of-file from a failed read so they kept paginating. It now returns the total line count with an explicit end-of-file message, and prefixes ranged reads with a (lines 350-428 of 428) header. Full-file reads are unchanged. (#20287)

  • Added a requireDelivery option to agent-controller session signals. When set, session.sendSignal waits for the agent to accept the wake signal and rejects if delivery fails, instead of resolving optimistically. This lets callers that need guaranteed delivery (like the Factory rule dispatcher) detect and retry failed kickoffs. (#20294)

    const result = session.sendSignal(
      { id, type: 'user', tagName: 'user', contents: message },
      { requestContext, requireDelivery: true },
    );
    // Resolves only once the agent has accepted the signal (`action` is
    // 'wake' or 'deliver'); rejects if the wake never reaches an agent.
    const { action, runId } = await result.accepted;
  • Observational-memory settings no longer fail with "No session for resourceId" on the settings page: OM config routes now treat the live session as best-effort sync and fall back to the durably stored per-user settings when no agent-controller session exists for the resource (e.g. after a server restart), so settings load and save instead of 404ing (#20265)

  • Fixed four bugs affecting split API and worker deployments: (#19652)

    Workflow resolution in distributed step execution — Workers now correctly resolve workflows by their internal ID, fixing silent failures when workflow IDs differ from their registration keys.

    Background task dispatch without worker competition — Added a mode option ('full' | 'producer' | 'worker') to BackgroundTaskManager so the API tier can dispatch tasks without consuming them. Mastra automatically selects 'producer' mode when workers are disabled or filtered.

    Background task execution engine — Background tasks now execute in-process on the worker that picks them up, instead of routing through the distributed orchestration pipeline.

    Agent tool registration for background tasks — Tools attached to an agent are now registered with the background task executor registry, so dedicated workers can resolve and execute them.

  • Fixed session creation ignoring an exact thread id when the session was already live. Requesting a session with a threadId now resumes or creates that exact thread even when another request (like an event subscription or message listing) created the session first, preventing 'Thread not found' errors for workspace threads. (#20265)

  • Fixed Factory sessions failing to start their kickoff run. Workspaces now recover automatically when the sandbox provider changes or a sandbox is wiped (the repository is re-cloned instead of failing), thread pages surface workspace preparation errors with a Retry button instead of hanging, and kickoff messages are now delivered to the session thread instead of silently failing with a permissions error. (#20265)

  • The factory-review skill now publishes its verdict on the pull request itself (gh pr review --approve / --request-changes with the full handoff body, falling back to a PR comment when GitHub rejects the review) instead of only posting the verdict in the Factory thread (#20265)

  • Fixed Mastra construction so failed storage initialization no longer causes unhandled promise rejections. (#20181)

  • Fixed xAI model router strings to use the Responses API so provider tools like web search work without manually creating an xAI model instance. (#20306)

  • Notifications now stop retrying after a delivery failure that will never succeed. (#20290)

    A notification whose delivery deterministically fails — a missing model, a rejected request context — used to be retried on every dispatch tick forever, because a failed delivery only incremented a counter and left the record pending. One production notification reached 288 delivery attempts against the same error.

    Delivery attempts are now capped. After 5 failures the notification is marked failed and is no longer picked up by the dispatcher:

    const [notification] = await storage.listNotifications({ threadId, status: 'failed' });
    
    notification.deliveryAttempts; // 5
    notification.lastDeliveryError; // 'No model selected. Use /models to select a model first.'

    failed is a new NotificationStatus, so notification inbox queries can filter for delivery failures that need attention. Transient failures are unaffected — they still retry, just no longer without bound.

@mastra/ai-sdk@1.7.0

Minor Changes

  • Added experimental smooth streaming support to handleChatStream(), chatRoute(), and toAISdkStream(). (#19792)

    const stream = await handleChatStream({
      mastra,
      agentId: 'weatherAgent',
      params,
      experimentalTransform: smoothStream({ chunking: 'word', delayInMs: 20 }),
    });

Patch Changes

@mastra/auth-cloud@1.2.3

Patch Changes

  • Fixed a race condition in the Mastra Cloud auth provider where two users signing in with SSO at the same time could receive each other's PKCE verifier cookies. Login state is now tracked per request, keyed by the OAuth state parameter, so concurrent logins can no longer cross-wire cookies. Fixes #20203 (#20233)

@mastra/auth-studio@1.3.3

Patch Changes

  • Speed up Factory hot paths: (#20261)

    • Much lower latency on authenticated requests — successful auth verifications are cached briefly instead of hitting the platform on every request, and credential verification requests time out after 15 seconds instead of hanging
    • Faster GitHub repository listing and connecting
    • Opening the same session concurrently no longer provisions duplicate sandboxes, and stuck sandbox commands now fail with a clear error instead of hanging
    • Factory run dispatching stays fast as work-item history grows

@mastra/clickhouse@1.13.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/client-js@1.35.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

  • Added the name and description fields to the DatasetExperiment type. The server already returned these values, so you can now read an experiment's name and description directly from listDatasetExperiments, listExperiments, and getDatasetExperiment — no cast needed. (#19256)

    const { experiments } = await client.listDatasetExperiments(datasetId);
    
    for (const experiment of experiments) {
      console.log(experiment.name, experiment.description);
    }

@mastra/cloudflare@1.6.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/cloudflare-d1@1.2.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

  • Fixed multi-thread message queries so included messages and pagination metadata are returned correctly. (#20303)

@mastra/code-sdk@1.1.0

Minor Changes

  • Added resolveProviderOMDefault to @mastra/code-sdk/onboarding/packs, which returns the small, cheap observational memory model for a provider, or the model you pass in when that provider has none. (#20298)

    The built-in OM packs are now a single table, so the list offered during onboarding and the per-provider default can no longer drift apart.

    import { resolveProviderOMDefault } from '@mastra/code-sdk/onboarding/packs';
    
    resolveProviderOMDefault('anthropic').modelId; // 'anthropic/claude-haiku-4-5'
    resolveProviderOMDefault('openai-codex').modelId; // 'openai/gpt-5.4-mini'
    resolveProviderOMDefault('xai', 'xai/grok-4.5').modelId; // 'xai/grok-4.5'
  • Added provider-aware observational memory defaults, so a controller started without a stored OM choice observes and reflects with the cheap model of a provider you can actually reach instead of the built-in Gemini default. (#20291)

    The helpers behind it are exported if you build your own surface on the SDK:

    import { hasExplicitOMConfiguration } from '@mastra/code-sdk/onboarding/om-settings';
    import { selectPreferredOMPack } from '@mastra/code-sdk/onboarding/packs';
    
    // Best OM pack across everything the user can reach, preferring a given provider
    selectPreferredOMPack({ anthropic: 'oauth', google: 'apikey' }, 'anthropic')?.modelId;
    
    // True once the user picked an OM model or pack themselves — never seed over it
    hasExplicitOMConfiguration(settings);

Patch Changes

@mastra/convex@1.5.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/dsql@1.2.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/duckdb@1.5.2

Patch Changes

  • Fixed severe CPU and memory spikes when listing traces from large DuckDB databases. (#20175)

    Opening the traces page in Studio (or calling the list traces / list branches APIs) against a multi-GB trace database previously decompressed the entire span_events table for every page load, poll, and scroll — pinning all CPU cores and ballooning memory by several GB per query. On multi-GB databases, trace list queries now use roughly 5x less CPU and stay within a bounded memory budget:

    • Page queries now scan only the time range containing the requested spans instead of the whole table
    • Filtered and custom-ordered queries (status, hasChildError, order by endedAt) now paginate on a narrow column set before reconstructing full span payloads
    • Delta polls now short-circuit when there is no new data

    Also added memoryLimit and threads options to DuckDBStore. DuckDB previously used its default memory budget of 80% of system RAM, which could push application servers into swap; it now defaults to 2GB. File-backed databases spill larger-than-memory operations to disk. Note that :memory: databases cannot spill, so if you run very large queries against an in-memory database, raise memoryLimit.

    const store = new DuckDBStore({
      path: 'mastra.duckdb',
      memoryLimit: '4GB', // default '2GB'
      threads: 2, // default: one per CPU core
    });

@mastra/dynamodb@1.2.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/factory@0.2.2

Patch Changes

  • Make shared-factory credentials discoverable and shareable. The providers config route now reports orgKey per provider (an org-wide API key exists, even when shadowed by a personal credential) and orgKeyAdmin on the envelope (whether the caller may write org-scoped keys). The Studio UI uses this to default factory-setup API keys to org scope, warn when a factory default model is backed by a personal-only credential, show Personal/Org key badges, and replace the composer with an actionable notice when the signed-in user has no credential for the factory default model's provider. (#20315)

  • Reopening a workspace no longer fails with "git pull failed: Not possible to fast-forward" when the sandbox workdir was left on a session branch that diverged from its upstream (or has no upstream / detached HEAD). That state is the session's local work, so materialization now keeps the checkout as-is and continues instead of erroring the thread page; genuine pull failures (auth, egress, corruption) still surface. (#20315)

  • Observational-memory settings no longer fail with "No session for resourceId" on the settings page: OM config routes now treat the live session as best-effort sync and fall back to the durably stored per-user settings when no agent-controller session exists for the resource (e.g. after a server restart), so settings load and save instead of 404ing (#20265)

  • Pin Factory session agents to their session workdir. The agent system prompt derives its working directory from state.projectPath, which for Factory sessions inherited the controller-global default — the web server's own checkout. Review agents would cd into the host repository and run gh pr checkout there, mutating the developer's working tree instead of the session sandbox. The session workspace factory now seeds projectPath/projectName with the resolved sandbox workdir when the session is created and self-heals live state on later requests. (#20320)

  • Fixed session creation ignoring an exact thread id when the session was already live. Requesting a session with a threadId now resumes or creates that exact thread even when another request (like an event subscription or message listing) created the session first, preventing 'Thread not found' errors for workspace threads. (#20265)

  • Made Factory session opens and rule-driven kickoffs resilient to platform sandbox failures: (#20294)

    • Skill kickoffs now wait for the agent to accept the wake signal (via the new requireDelivery option on session.sendSignal) and automatically retry when delivery fails — for example when a platform sandbox is unreachable. Previously kickoffs were marked as sent even when the wake never reached the agent, so review sessions ended up as permanently empty threads.
    • Exec calls in the repo materialize/checkout/worktree-setup path retry thrown transport errors with a 5xx status (up to 2 retries with backoff). When several platform sandboxes are provisioned concurrently, the workspace proxy can return a transient 5xx on exec while a VM is still booting; this previously failed the whole session open with "Platform proxy request failed with 500". Command failures are unaffected — they resolve with a non-zero exit code and are never retried.
    • A sandbox whose git preflight fails (git-missing) is now treated as poisoned: the workspace factory tears it down, clears the persisted binding, and retries once on a freshly provisioned sandbox. Previously a sandbox booted from a bare base image (e.g. when the provider's template build fails) was reattached forever, so every session open failed with "git is not installed in the sandbox".
    • Concurrent kickoff preparation no longer surfaces a spurious unique-constraint error: a losing preparer can collide on both the work item's source_key and the pending start's kickoff_key in sequence, so the insert-or-replay loop now retries once more before giving up.
  • Fixed Factory sessions failing to start their kickoff run. Workspaces now recover automatically when the sandbox provider changes or a sandbox is wiped (the repository is re-cloned instead of failing), thread pages surface workspace preparation errors with a Retry button instead of hanging, and kickoff messages are now delivered to the session thread instead of silently failing with a permissions error. (#20265)

  • The factory-review skill now publishes its verdict on the pull request itself (gh pr review --approve / --request-changes with the full handoff body, falling back to a PR comment when GitHub rejects the review) instead of only posting the verdict in the Factory thread (#20265)

  • Allow signed-out Factory pages to load their web app manifest and icon. (#20246)

  • Added a periodic merged-PR reconciler so review board cards can never get stuck when a merge event is missed. Every 5 minutes the platform GitHub worker lists still-open github-pr review cards, fetches the live pull request state from GitHub, and replays a missed merge through the normal rules ingress with a state-derived idempotency key — moving the card to Done (and notifying an active session, if any) exactly once. The sweep has its own switch, MASTRA_PLATFORM_GITHUB_RECONCILE_ENABLED (default on), and keeps running in a reconcile-only worker mode even when MASTRA_PLATFORM_GITHUB_POLLING_ENABLED=false. Sweep failures are logged and stay on cadence instead of retrying every poll tick. (#20315)

  • Move merged pull request Review cards to Done automatically. When a PR merge event binds to the PR's own Review card, the built-in rule now transitions the card to Done (delivering a note to the card's active session when one exists) instead of attempting to message a work session that may not exist. Merge events bound to a provenance-linked Work item still only remind that agent to assess completion and never auto-complete the Work item. (#20315)

    Pull requests closed without merging now clear off the board too: a new built-in pullRequestClosed rule moves the PR's Review card to Canceled, and the reconcile sweep replays missed closes (not just missed merges) so abandoned PRs no longer sit in Reviewing forever.

    The reconcile sweep is also scoped to factory-configured repositories: instead of probing every repository a GitHub installation exposes, it bulk-loads the (installation, repository) pairs linked to factory projects and only sweeps those, reporting the swept repository count in its summary log.

  • Changed the observational memory defaults a factory gets when you connect a provider: Google and DeepSeek now seed OM with their small, cheap model instead of the model you selected for the factory, matching what Anthropic and OpenAI already did. Providers without a cheap OM model keep using your selected model, and OM models you already set are still left untouched. (#20298)

  • Speed up Factory hot paths: (#20261)

    • Much lower latency on authenticated requests — successful auth verifications are cached briefly instead of hitting the platform on every request, and credential verification requests time out after 15 seconds instead of hanging
    • Faster GitHub repository listing and connecting
    • Opening the same session concurrently no longer provisions duplicate sandboxes, and stuck sandbox commands now fail with a clear error instead of hanging
    • Factory run dispatching stays fast as work-item history grows

@mastra/lance@1.2.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/libsql@1.18.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

  • Fixed Factory database lock errors by serializing writes that share a LibSQL connection. (#20278)

@mastra/memory@1.24.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/mongodb@1.15.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

  • MongoDBVector can now index an existing (operational) collection instead of a managed one. Pass collectionName (and optionally searchIndexName) to createIndex, and query with metadataMode: 'document' to get the full source document back as metadata. (#19805)

    Bring-your-own collections are read-only by default. The store never modifies or deletes caller-owned operational documents: upsert, updateVector, deleteVector, and deleteVectors throw a clear USER-category error on a BYO index unless it was created with allowWrites: true. The write policy is persisted alongside the index registration (surviving restarts) and fails closed for entries that predate it. Managed collections are unaffected and remain always writable.

    The bring-your-own index target (collection name, search-index name, and the isByo safety flag) is now persisted durably in a mastra-owned registry collection and hydrated on demand, so BYO classification survives a process restart: deleteIndex from a fresh process drops only the Atlas search index and never drops the caller's operational collection. listIndexes now returns logical Mastra index names (not physical collection names), so its output round-trips correctly back into deleteIndex/describeIndex. metadataMode: 'document' now returns a clean source document (the synthetic relevance score is no longer merged into metadata, so a real source field named score is preserved).

    Example

    await vectorStore.createIndex({ indexName: 'precedents', dimension: 1024, collectionName: 'transactions' });
    const hits = await vectorStore.query({ indexName: 'precedents', queryVector, metadataMode: 'document' });
  • MongoDBVector now supports full-text and hybrid retrieval. createSearchIndex provisions an Atlas Search index, textQuery runs a BM25 search, and hybridQuery fuses vector + text results server-side with $rankFusion (requires MongoDB 8.0+; on 8.0.x it may need a MongoDB support case to enable). (#19805)

    A custom or field-restricted text-search index name is now persisted and resolved automatically by textQuery/hybridQuery (with a per-call override), so a searchIndexName passed to createSearchIndex is reachable; when fields is supplied without an explicit name, the field-mapped index is created under a distinct name so its mapping is not shadowed by the auto-created dynamic index. hybridQuery's vector branch now reuses the same pushdown-vs-fallback filter logic as query, so metadata filters on undeclared fields no longer hard-error on bring-your-own collections.

    Hardening for bring-your-own (BYO) operational collections:

    • Full-text/hybrid search on a BYO collection is now opt-in: createIndex no longer auto-creates a billable dynamic full-text index on a caller-owned collection. Call createSearchIndex to enable textQuery/hybridQuery (which otherwise throw a clear error); managed collections keep auto-creating it for back-compat.
    • deleteIndex on a BYO index now also drops the companion full-text search index (when one was provisioned), not just the vector index, so it no longer leaks an untracked index onto the caller's collection. The collection and its documents are still preserved.
    • createIndex now throws a clear error when a logical index is retargeted to a different collection than the one already registered, instead of silently orphaning the previous collection's index; idempotent re-creation against the same collection still succeeds.
    • metadataMode: 'document' now omits the (large) embedding field from metadata by default; set includeVector: true to retain it and also expose it as a top-level vector. A real source field named score is still preserved.
    • BYO operational collections with native ObjectId _ids are now fully supported: query results coerce _id to a string (the QueryResult.id contract), and deleteVector/updateVector/deleteVectors accept that string and match the underlying ObjectId document. Managed (string _id) collections are unaffected.
    • In metadataMode: 'document', metadata filters now operate on root document fields instead of being rewritten to metadata.<field>, so filters like { lane: 'fraud' } match a BYO collection's top-level operational fields (both the pushdown and $match fallback paths). Managed 'field' mode keeps the metadata. rewriting.
    • The full-text search index builds asynchronously; a new waitForSearchIndexReady() (and a waitUntilReady option on createSearchIndex) blocks until the text index reports READY, so an immediate textQuery/hybridQuery no longer intermittently fails. The field-mapped default text-index name is now unique per logical index so two logical indexes on one collection no longer collide.
    • hybridQuery floors its vector-branch numCandidates at the branch limit, so numCandidates smaller than the internal limit no longer triggers a server-side error. describeIndex().count now counts only documents that actually carry the embedding field (relevant on BYO collections with a mix of embedded and non-embedded documents).
    • The $rankFusion support probe (buildInfo) is memoized per instance, and textQuery guards its score consistently with hybridQuery.

    Example

    await store.createSearchIndex({ indexName: 'precedents', fields: ['note'] });
    const hits = await store.hybridQuery({
      indexName: 'precedents',
      queryVector,
      query: 'shell company',
      paths: ['note'],
      topK: 10,
    });

Patch Changes

  • Temporarily pin bson to 7.2.0 to work around a hang in an edge case with the newer bson version. Will unpin shortly. (#20178)

@mastra/mssql@1.5.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/mysql@0.5.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

  • Fixed multi-thread message queries so included messages are resolved from their actual threads. (#20303)

@mastra/observability@1.16.3

Patch Changes

  • Logged observability exporter initialization failures instead of leaving rejected promises unhandled. (#20181)

@mastra/pg@1.18.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

  • Observational-memory settings no longer fail with "No session for resourceId" on the settings page: OM config routes now treat the live session as best-effort sync and fall back to the durably stored per-user settings when no agent-controller session exists for the resource (e.g. after a server restart), so settings load and save instead of 404ing (#20265)

  • Fixed session creation ignoring an exact thread id when the session was already live. Requesting a session with a threadId now resumes or creates that exact thread even when another request (like an event subscription or message listing) created the session first, preventing 'Thread not found' errors for workspace threads. (#20265)

  • Fixed a crash where the server process exited when an idle Postgres connection in the PgFactoryStorage pool dropped (for example after a network change or database restart). The pool now discards the broken connection, logs a warning, and reconnects on the next query. (#20265)

  • Fixed Postgres startup failures when multiple API and worker processes initialize the same schema simultaneously. (#19652)

  • Fixed Factory sessions failing to start their kickoff run. Workspaces now recover automatically when the sandbox provider changes or a sandbox is wiped (the repository is re-cloned instead of failing), thread pages surface workspace preparation errors with a Retry button instead of hanging, and kickoff messages are now delivered to the session thread instead of silently failing with a permissions error. (#20265)

  • The factory-review skill now publishes its verdict on the pull request itself (gh pr review --approve / --request-changes with the full handoff body, falling back to a PR comment when GitHub rejects the review) instead of only posting the verdict in the Factory thread (#20265)

@mastra/platform-workspace@0.2.2

Patch Changes

  • Added: Direct exec data plane for PlatformSandbox. (#20326)

    Commands now execute against Railway's WebSocket endpoint directly using a short-lived JWT lease minted by the workspace proxy, instead of proxying every exec through the HTTP proxy. This removes the workspace proxy from the exec hot path — cutting latency for large-payload commands (e.g. pnpm install) and eliminating duplicated observability spans.

    The change is transparent: executeCommand still returns the same CommandResult shape. If the proxy's /exec-lease endpoint is unavailable (older deployments), the client automatically falls back to the legacy POST /sandbox/:id/exec route for the lifetime of the sandbox.

  • Fixed platform sandbox reattach and made provisioning resilient to transient proxy failures: (#20294)

    • The workspace proxy assigns its own sandbox id on create (the advisory id in the request body is not honored), but getInfo() never exposed it, so callers persisting a reattach id (e.g. the Factory sandbox fleet, which reads metadata.sandboxId) stored the locally generated construction id instead. Every reattach then 404'd and each session open provisioned a brand-new sandbox and re-cloned the repository. getInfo() now reports the platform-assigned id in metadata.sandboxId, and start() treats a sandbox record with destroyedAt set as gone (falls through to a fresh provision) instead of pointing exec at a dead resource.
    • Sandbox creation retries transient workspace-proxy 5xx responses with a short backoff. Provisioning intermittently fails with proxy 500s while the provider is under load; a retry keeps a single flaky window from failing the caller's whole workflow (e.g. Factory kickoff runs). Non-transient errors (4xx) still fail immediately.

@mastra/playground-ui@44.0.0

Patch Changes

  • Clarified the trace intelligence terminology in the Signals empty state. (#20268)

  • Fixed Sankey chart labels overlapping between neighbouring columns on narrow charts. Node names and column headers are now measured against the space each column actually has, and a label that no longer fits is clipped with an ellipsis. Hovering a clipped label still shows its full text. (#20289)

@mastra/redis@1.3.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/server@1.54.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

  • Fixed A2A message/send requests with configuration.blocking set to false so they return a working task while execution continues. (#20205)

@mastra/slack@1.6.0

Minor Changes

  • Slack connections can now be owned by an AgentController, not just a registered Agent. Call connect with an options object to connect an owner that has no registered agent: (#19289)

    await mastra.channels.slack.connect({
      id: 'my-controller',
      name: 'Support Bot',
    });

    Installations record an ownerType ('agent' by default, or 'agentController'). Inbound Slack events and OAuth callbacks route to the owning AgentController's channels when ownerType is 'agentController', so mentions and messages drive a controller session. Existing agent-owned installations are unaffected.

Patch Changes

@mastra/spanner@1.4.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

@mastra/upstash@1.3.0

Minor Changes

  • Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. (#19991)

    const messages = await memory.recall({
      threadId: 'thread-1',
      filter: {
        metadata: {
          status: 'done',
          priority: 'high',
        },
      },
    });

    Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and null.

Patch Changes

  • Fixed multi-thread message queries so pagination metadata accounts for all queried threads. (#20303)

Other updated packages

The following packages were updated with dependency changes only:

Don't miss a new mastra release

NewReleases is sending notifications on new releases.