github mastra-ai/mastra @mastra/core@1.71.0
September 24, 2026

6 hours ago

Highlights

Observability Capabilities Negotiation (Storage ↔ Server ↔ Client)

Servers now expose observabilityStorageCapabilities (via GET /system/packages and the new GET /observability/capabilities) so Studio/clients can detect which observability APIs a configured store actually supports—covering per-endpoint discovery flags plus traceQuery, threadQuery, deltaPolling, and more—without forcing storage upgrades.

Discovery-Backed Observability Filters & Feature Declarations

Observability stores can now declare supported features via getFeatures() (including entity/service/environment/tag/metric discovery), letting Studio only call compatible endpoints; VNext stores and Oracle now report discovery support, and discovery routes return empty results (not 500s) when unsupported.

Trace Aggregation Planning API for Backends

planTraceAggregate() validates and converts an aggregateTraces() request into a TrustedTraceAggregatePlan that any storage backend can execute without re-validating, enabling consistent query behavior and clearer validation errors across storage implementations.

Eager Tool Execution for Faster Streaming Runs

Tool calls now start as soon as their own arguments are complete (instead of waiting for the model to finish streaming the whole step), cutting idle time in multi-tool steps; can be disabled per run (and is now supported in stored agent default options).

New Integrations: Discord Channel + Sandbox Credential Materialization

Added @mastra/discord to connect agents to Discord (slash commands, DMs, mentions, encrypted token-at-rest), and @mastra/connect environment() to materialize Platform connection credentials into { env, onStart } for authenticated tooling inside sandbox providers (e2b/Modal/Daytona/Docker/subprocess).

MongoDB Vector “Automated Embeddings” (Server-Side Embedding Generation)

MongoDBVector now supports Automated Embeddings: create an autoEmbed index (e.g. Voyage) and then write plain text + search with queryText, with MongoDB generating embeddings server-side (no embedding provider wiring or dimension bookkeeping in your app).

Breaking Changes

  • @mastra/playground-ui TaskList API: title, TaskListHeader, and hideWhenEmpty are removed.

Changelog

@mastra/core@1.71.0

Minor Changes

  • Added per-endpoint discovery features that observability storage can declare from getFeatures(): entity-type-discovery, entity-name-discovery, service-name-discovery, environment-discovery, tag-discovery and metric-discovery. The in-memory observability store now declares metrics, logs and discovery support. (#25008)

    Custom observability stores can declare what they support so Studio only calls those APIs:

    import { ObservabilityStorage } from '@mastra/core/storage';
    
    class MyObservabilityStore extends ObservabilityStorage {
      override getFeatures() {
        return ['logs', 'entity-name-discovery', 'tag-discovery'] as const;
      }
    }
  • Added planTraceAggregate(). It checks a parsed aggregateTraces() request and returns a TrustedTraceAggregatePlan that any storage backend can execute without re-validating the request. (#24868)

    import { parseTraceAggregateRequest, planTraceAggregate } from '@mastra/core/storage';
    
    const plan = planTraceAggregate(parseTraceAggregateRequest(request), {
      scope: { organizationId: 'org_123' },
    });
    // plan.dimensions, plan.measures, plan.having, plan.orderBy, plan.limit, plan.where

    Validation rules

    • timeRange and where are validated exactly like queryTraces().
    • groupBy accepts only supported dimensions.
    • countDistinct accepts traceId or any field that groupBy accepts.
    • having can reference a requested measure or count.
    • orderBy can reference a requested measure, a requested dimension, or count. bucket is not an ordering target.
    • The time range can be at most 365 days.
    • An interval can touch at most 1000 UTC-aligned buckets, and limit × buckets can be at most 10,000 rows.

    having, orderBy, and limit apply to groups using measures computed over the whole time range; with an interval, each returned group is a complete series in bucket order. The plan's JSDoc spells this out for backends.

    Invalid requests throw TraceQueryValidationError with the same issue codes and JSON paths as planTraceQuery(). The new too_many_buckets code names the smallest permitted interval; too_many_rows asks the caller to lower limit or widen interval.

Patch Changes

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

  • Tools now start as soon as their own arguments are complete, instead of waiting for the model to finish streaming the whole step. This is on by default and removes seconds of idle time from steps that call several tools. (#25005)

    // Default: each tool starts as soon as its call is complete.
    const eager = await agent.stream('Compare the weather in Paris and Rome');
    
    // Opt out to restore the previous scheduling.
    const deferred = await agent.stream('Compare the weather in Paris and Rome', {
      eagerToolExecution: false,
    });

    These calls still wait for the model to finish: tools that need approval, declare a suspend schema, run on the provider or client, or run in the background, and runs that use the called concurrency strategy or output processors that run after the stream. A tool that already finished is never run again and its result is always kept, including on retry, fallback, and abort.

    A tool still running when an attempt is retried, falls back, or is aborted finishes first, and its result is kept.

    A tool that calls suspend() at runtime also runs once: the run suspends instead of retrying the model. See the stream() reference for the full rules.

  • Added a feedback observability storage feature so clients can identify whether a store supports the feedback APIs. Storage adapters that implement the feedback methods declare the feature to advertise support. (#25020)

    import { ObservabilityStorage } from '@mastra/core/storage';
    
    class MyObservabilityStore extends ObservabilityStorage {
      public getFeatures() {
        return ['feedback'] as const;
      }
    }
  • Fixed the Workspace example to use current providers and distinguish local paths from cloud mount paths. (#24988)

  • Fixed a denial-of-service risk in dataset schema validation. Regex pattern and patternProperties in dataset input and ground truth schemas now run on a linear-time (RE2) engine, so a crafted pattern can no longer freeze the server. Fixes #24981. (#25044)

    Behavior changes

    • Patterns using syntax RE2 cannot run, such as lookarounds ((?=...), (?<!...)) and backreferences (\1), are rejected with a DATASET_SCHEMA_PATTERN_UNSUPPORTED error when the dataset is created or its schema is updated. Escapes such as \uXXXX and \cX keep working.
    • Matching is Unicode-aware: . matches a whole code point (so ^.$ matches 😀), and \p{L} is a Unicode class even without the u flag.

    To migrate, rewrite affected patterns without lookarounds or backreferences, for example replace pattern: '^(?=.*\\d).+$' with pattern: '\\d', then update the dataset schema.

@mastra/ai-sdk@1.10.5

Patch Changes

  • Fixed v7 helpers (handleChatStream, chatRoute, toAISdkStream, toAISdkMessages with version: 'v7') rejecting UIMessage values from ai@7.0.103 and later. These versions type providerMetadata with readonly JSON values, which the bundled v7 types did not accept. You no longer need to stay on ai@7.0.102 or cast messages. (#24931)

@mastra/auth-google@0.1.5

Patch Changes

  • Fixed Google SSO users being signed out after about an hour. Sessions now last for the configured session.cookieMaxAge (24 hours by default) instead of expiring with the short-lived Google ID token. (#25043)

@mastra/clickhouse@1.21.1

Patch Changes

  • Fixed slow feedback review-status updates on ClickHouse. Since 1.21.0, each update ran a ClickHouse mutation that scanned every part of the feedback table, taking several seconds on tables with months of daily partitions and timing out on larger ones. Review updates now write a new row again, which takes milliseconds regardless of table size. (#25000)

    Upgrade note: the runtime database user no longer needs ALTER UPDATE(reviewStatus) on mastra_feedback_events or INSERT on mastra_feedback_events_delta for review updates. Grants you added for 1.21.0 are harmless. Keep ALTER UPDATE if you run ClickHouse 26.6 or earlier, because lightweight deletes still need it there.

    Deleted feedback still can't reappear through a review update: an update that lands during a delete of the same feedback retries the delete and reports the feedback as not found. A failed delete no longer blocks review updates: the next update saves the new status, then retries the delete and reports its error if it fails again. If a network error or a lagging replica lets a review row outlive a successful delete, the next review update of that feedback removes it.

  • Declared feedback support in the observability store so servers report the feedback capability as available to clients. (#25020)

    // With one of these stores configured as the observability storage:
    const { capabilities } = await client.getObservabilityCapabilities();
    
    console.log(capabilities.feedback); // true

    Also in: @mastra/duckdb@1.11.1, @mastra/pg@1.27.1

  • The observability stores used by PostgresStoreVNext, ClickhouseStoreVNext and DuckDBStore now declare their filter discovery support, so Studio can show discovery-backed filters based on what the store reports. (#25008)

    const { capabilities } = await client.getObservabilityCapabilities();
    capabilities.discovery; // { entityTypes: true, entityNames: true, serviceNames: true, environments: true, tags: true, metrics: true }

    Also in: @mastra/duckdb@1.11.1, @mastra/pg@1.27.1

@mastra/client-js@1.50.0

Minor Changes

  • Added getObservabilityCapabilities(), which returns the optional observability features the server's configured storage supports. (#25008)

    const { observabilityStorageType, capabilities } = await client.getObservabilityCapabilities();
    
    if (!capabilities.traceQuery) {
      // List traces with the legacy endpoint instead
      const traces = await client.listTracesLight({ pagination: { page: 0, perPage: 25 } });
    }

Patch Changes

  • Stopped retrying requests that fail with 501 Not Implemented. The server returns 501 when the configured storage does not support an API, so retrying only added repeated failed requests and server error logs. (#25008)

  • Added a feedback flag to the observability capabilities response so you can check whether the configured store supports the feedback endpoints before calling them. (#25020)

    const { capabilities } = await client.getObservabilityCapabilities();
    
    if (capabilities.feedback) {
      const feedback = await client.listFeedback({ traceId });
    }

@mastra/code-sdk@1.8.3

Patch Changes

  • Stagehand model selection now follows your chat setup instead of a hardcoded fallback. (#25028)

    • Added resolveStagehandModel() to report which model Stagehand will use and why. It resolves, in order: browser.stagehand.model (settings), the chat model captured at browser launch when Stagehand can route it (chat-model), the OpenAI Codex default model when you are signed in with Codex (codex-oauth), then Stagehand's own default (stagehand-default).
    • Any openai/* model, configured or inferred, now goes through the Codex endpoint when your OpenAI login is Codex OAuth, with the same -codex model-id remaps the chat agents apply. Codex-only users no longer need a separate OPENAI_API_KEY for browser automation.
    • Dotted Anthropic ids such as anthropic/claude-opus-4.6 are normalized before being handed to Stagehand, matching the chat agents.
    • Fixed the Browserbase API key being saved in session state; the active-browser snapshot is now credential-free and records which model the browser launched with.
    import { resolveStagehandModel } from '@mastra/code-sdk/onboarding/settings';
    
    const { modelName, source, viaCodexOAuth } = resolveStagehandModel(settings.browser, {
      chatModelId: session.model.get(),
    });
    // e.g. { modelName: 'anthropic/claude-sonnet-4-5', source: 'chat-model', viaCodexOAuth: false }

@mastra/connect@0.4.0

Minor Changes

  • Add environment() for sandboxed agents. Materialize provider credentials from your project's Platform connections into a { env, onStart } pair that any sandbox provider (e2b, Modal, Daytona, Docker, subprocess) can consume — so CLI tooling inside the sandbox is authenticated without hand-wiring tokens per agent. (#24912)

    import { environment } from '@mastra/connect';
    
    const env = environment({
      projectId: process.env.MASTRA_PROJECT_ID,
      client: { accessToken: process.env.MASTRA_PLATFORM_ACCESS_TOKEN },
    });
    
    const { env: envVars, onStart } = await env();
    
    await sandbox.start({ env: envVars, onStart });

    environment() shares its resolution model with connect(): same projectId, client, and per-provider integrations overrides (connectionId to pin, disabled: true to exclude). GitHub is the first provider with an env contributor — its OAuth token is exported as GH_TOKEN/GITHUB_TOKEN so both gh and git HTTPS authenticate as the connected user, and onStart installs a git credential helper that reads the token from the environment rather than baking it into git config.

@mastra/discord@1.1.0

Minor Changes

  • Added @mastra/discord for connecting Mastra agents to Discord. One Discord app serves many servers, and agents respond to slash commands, DMs, and @mentions. Set encryptionKey or MASTRA_ENCRYPTION_KEY to encrypt the stored bot token at rest. (#25002)

    import { Mastra } from '@mastra/core';
    import { DiscordProvider } from '@mastra/discord';
    
    // App credentials from the Discord Developer Portal (or the DISCORD_BOT_TOKEN /
    // DISCORD_PUBLIC_KEY / DISCORD_APPLICATION_ID env vars):
    const discord = new DiscordProvider({
      app: {
        botToken: process.env.DISCORD_BOT_TOKEN!,
        publicKey: process.env.DISCORD_PUBLIC_KEY!,
        applicationId: process.env.DISCORD_APPLICATION_ID!,
      },
    });
    
    export const mastra = new Mastra({
      agents: { support },
      channels: { discord },
    });
    
    // Bind an agent. If the bot is already in DISCORD_GUILD_ID, this binds the
    // agent to that guild and registers its slash commands immediately. Otherwise
    // it returns an OAuth2 bot-invite URL and the install stays pending until the
    // bot joins a guild — the first interaction from that guild activates it.
    const result = await discord.connect('support', { guildId: process.env.DISCORD_GUILD_ID });
    // → { type: 'immediate' }  OR  { type: 'oauth', authorizationUrl, installationId }

@mastra/duckdb@1.11.1

Patch Changes

  • Fixed completed event spans appearing to still be running, including event spans stored before this fix. Event spans now report an end time equal to their start time, matching the ClickHouse and PostgreSQL stores. (#24970)

  • Fixed listTraces, listTracesLight and listBranches on @mastra/duckdb so each trace and branch is counted once. Every ended span is stored with two start rows, and the fast path and delta polling counted both. pagination.total was double the real number, each page returned about half of perPage, a trace could show on two pages, and delta polls returned every trace twice. Fixes #24919 (#24932)

@mastra/elysia@0.1.11

Patch Changes

  • Handler errors with status 501 Not Implemented are now logged as warnings instead of errors. A 501 means the configured storage does not support an optional feature, not a server failure. (#25008)

    Also in: @mastra/express@1.5.15, @mastra/fastify@1.5.15, @mastra/hono@1.7.13, @mastra/koa@1.7.15

@mastra/evals@1.10.3

Patch Changes

  • Fixed faithfulness and hallucination scorers returning inflated scores when the judge model returned fewer verdicts than extracted claims. Scores are now divided by the number of claims, so claims without a verdict are no longer silently dropped. Verdicts are also matched case-insensitively, so "Yes" is counted the same as "yes". (#25039)

@mastra/express@1.5.15

Patch Changes

  • Fixed refreshed session cookies being lost in the standalone createAuthMiddleware for Express, Fastify, Hono, and Koa. Browsers now receive the refreshed Set-Cookie on both allowed and denied requests. Fixes #24963. (#25024)

    Also in: @mastra/fastify@1.5.15, @mastra/hono@1.7.13, @mastra/koa@1.7.15

@mastra/factory@0.17.2

Patch Changes

  • Check missing external issues again after 24 hours to reduce repeated requests (#24973)

  • Keep integration arrivals in Intake until someone starts them. (#24983)

    Before: trusted issue and pull request arrivals could create triage or review proposals, and unbound Linear, Jira, and incident.io cards landed in Triage. After: integrations stay in the routed board's initial phase without starting or suggesting a run (except explicit trusted review requests, which land directly in Reviewing). To restore automatic arrival triage, configure a custom board's initial-phase handler:

    import { MastraFactory } from '@mastra/factory';
    import type { MastraFactoryConfig } from '@mastra/factory';
    import { defineBoard } from '@mastra/factory/boards';
    
    const customWorkBoard = defineBoard({
      id: 'custom-work',
      title: 'Custom Work',
      initialPhase: 'intake',
      phases: {
        intake: {
          title: 'Intake',
          kind: 'resting',
          onEnter: {
            issue: context =>
              context.cause === 'linked_item_materialized' && context.item.metadata?.autoStartCandidate === true
                ? {
                    type: 'invokeSkill',
                    idempotencyKey: `${context.ingress.id}:factory-triage`,
                    role: 'triage',
                    skillName: 'factory-triage',
                  }
                : undefined,
          },
        },
        triage: { title: 'Triage', kind: 'working', role: 'triage' },
      },
    });
    
    export function createFactory(storage: MastraFactoryConfig['storage']) {
      return new MastraFactory({ storage, boards: [customWorkBoard] });
    }

@mastra/fastembed@1.3.2

Patch Changes

  • Built-in FastEmbed models now download from Hugging Face (Qdrant organization) instead of the legacy Qdrant Google Cloud Storage bucket, which is being shut down. Existing local model caches keep working. (#25026)

@mastra/koa@1.7.15

Patch Changes

  • Fixed duplicate console.error output for handler errors with status 501 Not Implemented on Koa. Custom app.on('error') listeners still receive these errors. (#25015)

@mastra/libsql@1.23.3

Patch Changes

  • Fixed create in LibSQL skills storage to include visibility in the returned skill. (#25031)

@mastra/mcp-docs-server@1.3.1

Patch Changes

  • Fixed embedded documentation tools to reject empty and relative project paths with clear validation errors. (#24969)

@mastra/memory@1.32.1

Patch Changes

  • Fixed Observational Memory saving working memory that does not match your configured workingMemory.schema. When observation.manageWorkingMemory is enabled, the observer now checks each working memory update against the schema before saving it. An update with values outside an allowed list, wrong types, missing required fields, or disallowed extra fields is skipped, and the previous working memory is kept. A null in a field the schema marks optional is treated as not provided, the same as with the working memory tool. Returning null still leaves working memory unchanged. Fixes #24240. (#24926)

@mastra/mongodb@1.19.0

Minor Changes

  • Added Automated Embedding support to MongoDBVector. Create an index with autoEmbed and a Voyage AI model such as voyage-4, then write plain text through documents and search with queryText. MongoDB generates the embeddings server-side, so your application needs no embedding provider, no model wiring, and no dimension bookkeeping. (#24383)

    await store.createIndex({ indexName: 'movies', autoEmbed: { model: 'voyage-4' } });
    await store.upsert({ indexName: 'movies', documents: ['A lonely astronaut adrift near Saturn.'] });
    const results = await store.query({ indexName: 'movies', queryText: 'space opera', topK: 5 });

    hybridQuery accepts queryText for its vector branch, and both query methods take an optional model to override the index's model for a single search. Indexes that supply their own vectors keep working exactly as before.

    Automated Embedding is a MongoDB Preview feature. It requires an Atlas cluster with Automated Embedding enabled, or the mongodb/mongodb-atlas-local:preview image locally.

@mastra/mysql@0.10.2

Patch Changes

  • Fixed skill visibility not being persisted by MySQL storage, so skills marked public are now readable by other users and returned by list({ visibility: 'public' }). (#25031)

@mastra/nestjs@0.2.30

Patch Changes

  • Fixed @mastra/nestjs to run the same auth pipeline as the other server adapters. Cookie-based sessions now authenticate, custom routes registered with registerApiRoute() are served (honoring requiresAuth), and mapUserToResourceId is applied to the request context. Fixes #24964. (#25027)

@mastra/observability@1.18.1

Patch Changes

  • Fixed event spans (such as model_chunk spans for tool-result and tool-call-approval chunks) being stored and exported with endedAt: null in completed runs, which made them look like they were still running. Event spans are point-in-time, so they now end at the instant they start: endTime equals startTime and their duration is zero. Event spans no longer emit duration metrics. Fixes #24233. (#24970)

@mastra/oracledb@0.4.1

Patch Changes

  • The Oracle observability store now declares its logs and filter discovery support (entity types, entity names, service names, environments and tags), so Studio can show the matching filters. (#25008)

    const { capabilities } = await client.getObservabilityCapabilities();
    capabilities.logs; // true
    capabilities.discovery.entityNames; // true

@mastra/otel-bridge@1.5.11

Patch Changes

  • Fixed OtelBridge silently exporting nothing when no OpenTelemetry tracer provider is available. The bridge now logs one clear warning that explains how to register a tracer provider or pass one with new OtelBridge({ tracerProvider }), and links to the setup docs. It no longer logs a warning for every span. Mastra spans also no longer reuse an outer span's ID when that outer span comes from a tracer provider that isn't registered. Fixes #24950. (#24986)

@mastra/pg@1.27.1

Patch Changes

  • Fixed PostgresStore and PgVector rejecting schema names that are only valid when quoted, such as my-tenant. Any schema name up to 63 bytes is now accepted, as long as it has no quotes, backslashes, $, or control characters. Index and constraint names built from the schema use a sanitized prefix (my-tenant becomes my_tenant_...), so existing schemas keep their current index and constraint names. (#25045)

@mastra/playground-ui@59.0.0

Minor Changes

  • Added InlineCode for code inside a sentence, and documented when to use monospace text. (#25012)

    Code is always marked as code: InlineCode in running text, and a highlighted CodeBlock for anything longer. Txt font="mono" is for machine identifiers such as model IDs, hashes, and log lines, and for timestamps and durations. Other numbers, such as counts and costs, stay in the body face with tabular-nums. It keeps the role's size, line height, and weight and changes only the typeface. DataList.NumberCell takes font="mono" for duration columns, and trace and workflow durations now render in mono. KPI values and chart axes stay in the body face.

    import { InlineCode } from '@mastra/playground-ui/components/InlineCode';
    import { Txt } from '@mastra/playground-ui/components/Txt';
    
    <Txt variant="body-sm" tone="muted">
      Set <InlineCode>OPENAI_API_KEY</InlineCode> to use this model.
    </Txt>
    
    <Txt variant="caption" font="mono" tone="muted">
      run_01JQX8K2M4
    </Txt>

    Txt now accepts font="body", the default, alongside font="mono". Set --font-mono in your own CSS to use a different monospace typeface. Set --font-mono-size-adjust to the body face's x-height ratio, such as ex-height 0.508, so mono text looks the same size as the text around it.

  • Added required and errorMsg to SettingsRow. A required row shows the same asterisk as a form field label, and an error message appears under the label as an alert the control can reference. (#24980)

    <SettingsRow label="Model" htmlFor="model" required errorMsg="Choose the model this agent runs on.">
      <Input id="model" error aria-describedby={fieldErrorId('model')} />
    </SettingsRow>
  • Added RelativeTimestamp, which shows a compact relative time such as 3m ago or in 2h in monospace. Hover or focus shows a card with the time since, counting up live, and the date and time in your timezone and in UTC. Studio schedules, trigger history, and workflow run headers now use it. (#25001)

    import { RelativeTimestamp } from '@mastra/playground-ui/components/RelativeTimestamp';
    
    <RelativeTimestamp value={run.createdAt} />;
  • Added CompactNumber, which shows a compact metric such as 12.3K or $1.2K and reveals the full value (12,310) in a tooltip on hover or focus. The compact value can hide digits ($123.45 shows as $123), and the full value in the tooltip keeps the currency's precision. An amount smaller than the currency's smallest unit shows as <$0.01, and a unit that isn't a currency, such as credits, shows as a plain number. (#24979)

    import { CompactNumber } from '@mastra/playground-ui/components/CompactNumber';
    
    <CompactNumber value={12310} />
    <CompactNumber value={12345.67} currency="USD" />

    The number and cost formatters now live in one place, @mastra/playground-ui/utils/cost. formatCompact is renamed to formatCompactNumber, and formatCompact and formatCost are no longer exported from the metrics components.

    // Before
    import { formatCompact, formatCost } from '@mastra/playground-ui/domains/metrics/components';
    
    // After
    import { formatCompactNumber, formatCost, formatFullNumber } from '@mastra/playground-ui/utils/cost';
  • Status dots use one circular shape. StatusDot and Status now draw every state as a circle. Meaning comes from color plus a filled or ring treatment. The square and dashed glyphs and the blue idle tone are removed. (#24960)

    Canonical deploy states. deployStates exports the six deploy and server states: Ready, Building, Idle, Queued, Stopped, and Error. Idle and Queued are gray rings, Stopped is a gray filled dot.

    // Before
    { label: 'Stopped', tone: 'neutral', glyph: 'square', description }
    { label: 'Idle', tone: 'idle', description }
    
    // After
    { ...deployStates.stopped, description }
    { ...deployStates.idle, description } // { tone: 'neutral', glyph: 'ring' }

    Status labels inherit text style. The label now always takes the size and color of its container, so it matches the other cells in a DataList without a wrapper. The children slot is removed; style the container instead.

    // Before
    <Status presentation={presentation}>
      <Txt as="span" variant="body-sm">{presentation.label}</Txt>
    </Status>
    
    // After
    <Status presentation={presentation} />
  • TaskList no longer shows a spinner for the task in progress, which read as something loading. The active task now steps out onto its own lane of a small graph drawn beside the list, and its label fades into a warm gradient. A completed task's strike draws in from the left and erases cleanly if the task reopens. Every change between states is animated, and nothing moves when reduced motion is on. (#24947)

    Collapsed, the list is a one-row window on the current task, with the progress bars beside it. Expanding grows that window: the current task slides into place while the tasks around it come into view, and the progress bars fold away. The whole collapsed card expands on click.

    When the active task changes, the list scrolls itself smoothly to keep that task visible, instead of also scrolling the page or chat around it.

    Breaking

    • title is removed, since the list no longer has a header. Drop the prop.

    • TaskListHeader is removed. TaskList now renders its own toggle.

    • hideWhenEmpty is removed. An empty TaskList always renders nothing. Drop the prop:

      - <TaskList tasks={tasks} hideWhenEmpty={false} />
      + <TaskList tasks={tasks} />

Patch Changes

  • Field error messages now show an alert icon before the text, so an invalid field no longer relies on red alone. This applies to every field block, Combobox, and anything that renders FieldBlock.ErrorMsg. (#24987)

  • Fixed Studio timestamps losing their time on historical dates. Date-only cells now stay date-only even today, while trace tooltips and unnamed chat threads preserve seconds. Timeline timestamps use the browser locale while keeping UTC. Calendar labels respect the requested timezone at year boundaries. (#24955)

    Added shared date, duration, and elapsed-time helpers for custom Studio interfaces. formatDate requires an explicit preset: date, date-time, date-time-seconds, time, time-seconds, or relative-time. Trace list dates, table timestamps, and tool-call timestamps preserve visible seconds without requiring a hover. Relative labels fall back to the date preset after seven days. formatTimestampPrecise retains milliseconds for debugging.

    import { formatDate } from '@mastra/playground-ui/utils/date-format';
    import { formatDuration } from '@mastra/playground-ui/utils/duration';
    import { formatRelativeTime } from '@mastra/playground-ui/utils/relative-time';
    import { useElapsedTime } from '@mastra/playground-ui/hooks/use-elapsed-time';
    
    formatDate('2026-09-24T10:00:00Z', 'date-time-seconds', { timeZone: 'UTC' });
    formatRelativeTime('2026-09-24T10:00:00Z');
    formatDuration(1234); // "1.23s"
    
    function Elapsed({ isRunning }: { isRunning: boolean }) {
      const elapsed = useElapsedTime(isRunning);
      return <span>{formatDuration(elapsed)}</span>;
    }
  • Added a useObservabilityCapabilities hook (@mastra/playground-ui/domains/capabilities) that reads which observability features the server supports. Studio's traces page now uses it to list traces through the lightweight endpoint when the server doesn't support trace queries. Older servers that don't report capabilities keep the current behavior. (#25014)

    Also added useTraceQueryAvailable, which returns { isLoading, enabled }. enabled is false while capabilities load and when the server doesn't support trace queries. Studio uses it to pick the traces list endpoint and to hide feedback on servers without trace query support.

    Also exported useTracesListSource from @mastra/playground-ui/domains/traces, so other apps can rebuild the traces list (auto-refresh, rolling time window, list rows). It takes withQueryTrace and enabled as inputs and does not read capabilities itself; callers decide which endpoint to use.

  • PageHeader.Meta now renders plain text as muted meta text, so metadata next to a page title no longer competes with the title. Badges and other components that set their own text style are unchanged. The medium Badge now sets its own letter spacing, so it looks the same inside styled text as anywhere else. (#24985)

  • Added a defaultOpen option to the reasoning block (Reasoning and ReasoningPartRenderer), so apps can start reasoning collapsed. It defaults to true, so existing views are unchanged. While reasoning streams, the "Reasoning" label now shimmers, so a collapsed block still shows the model is thinking. (#25036)

    <ReasoningPartRenderer part={part} defaultOpen={false} />
  • Added a withQueryTrace option for servers that do not support the trace query API. Set it to false to list traces through the older light trace list endpoint: (#25007)

    • useTraceQuery accepts withQueryTrace and legacyFilters (built with buildTraceListFilters).
    • createTraceFilterBarFields only offers fields the light endpoint can filter on, with the is operator.
    • TraceColumnsMenu hides the "Add metadata column" action.
  • Studio hides the trace/span Feedback tab when the observability store does not support feedback. (#25020)

@mastra/server@1.71.0

Minor Changes

  • Studio and other clients can now tell which observability features the configured storage supports, without upgrading older storage packages. GET /system/packages now always returns observabilityStorageCapabilities when observability storage is configured. It adds per-endpoint discovery flags plus traceQuery, threadQuery, deltaPolling, traceQueryRootDuration and traceQueryTenantScope. (#25008)

    Stores that declare their features with getFeatures() are reported exactly as declared. Stores that predate feature declarations are detected by the methods they implement.

    On legacy stores such as LibSQL or the default PostgresStore, traceQuery is false. Clients should list traces with GET /observability/traces/light instead of POST /observability/traces/query on those stores (#24990).

    The same capabilities are also available from the new GET /observability/capabilities endpoint, which works on any @mastra/core version and reports every flag as false when no observability storage is configured.

    const { capabilities } = await client.getObservabilityCapabilities();
    
    if (capabilities.discovery.entityNames) {
      const { names } = await client.getEntityNames({});
    }

    Discovery routes (/observability/discovery/*) now return empty results instead of a 500 error when the storage does not support them. This stops the recurring "does not support entity name discovery" errors when opening Studio (#16304).

Patch Changes

  • Stored agent default options now accept eagerToolExecution. (#25005)

    defaultOptions: {
      eagerToolExecution: false,
    }
  • Fixed dataset create and update routes returning 500 when a schema uses an unsupported regex pattern; they now return 400 with the offending pattern. (#25044)

  • Added a feedback observability storage capability and clearer errors for unsupported storage APIs. (#25020)

    • GET /observability/capabilities and GET /system/packages now report a feedback flag, so clients can check feedback support before calling the feedback endpoints.
    • Observability routes backed by an optional storage API (feedback, metrics, logs, scores) now return a 501 status instead of a server error when the configured store does not implement it. This also removes the noisy error log Studio triggered when probing feedback on stores without it (for example LibSQL).
    const { capabilities } = await client.getObservabilityCapabilities();
    
    if (capabilities.feedback) {
      const feedback = await client.listFeedback({ traceId });
    }

@mastra/spanner@1.8.2

Patch Changes

  • The Spanner observability store now reports metrics and metric discovery as supported only when metrics are enabled with disableMetrics: false. Previously Studio could treat metrics as available while every metric request failed. (#25008)

    const { capabilities } = await client.getObservabilityCapabilities();
    capabilities.metrics; // true only when the SpannerStore sets disableMetrics: false

@mastra/telegram@0.1.3

Patch Changes

  • Fixed Telegram webhook connections so reusing a bot token for another agent is rejected instead of replacing the existing webhook. Clarified how connect() uses a default bot token. (#24912)

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.