fix(auth-okta): build correct endpoint URLs for Okta org authorization servers#1
Open
noahjohnhay wants to merge 1384 commits into
Open
fix(auth-okta): build correct endpoint URLs for Okta org authorization servers#1noahjohnhay wants to merge 1384 commits into
noahjohnhay wants to merge 1384 commits into
Conversation
| this.clientSecret = clientSecret; | ||
| this.issuer = issuer ?? `https://${domain}/oauth2/default`; | ||
| // Normalize trailing slashes so a stray `OKTA_ISSUER=https://domain/` doesn't produce `.../oauth2//v1/...` | ||
| this.issuer = (issuer ?? `https://${domain}/oauth2/default`).replace(/\/+$/, ''); |
## Description 1 day will be the default for pnpm v11 but since we still use pnpm v10 let's set it ourselves for now. The [minimumReleaseAge](https://pnpm.io/settings#minimumreleaseage) setting defines the minimum number of minutes that must pass after a version is published before pnpm will install it. ## Related issue(s) <!-- Required: Link to the issue(s) this PR addresses, e.g. with: Fixes mastra-ai#123. PRs without linked issues may be closed. --> ## Type of change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [ ] I have linked the related issue(s) in the description above - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR
) ## Description <!-- Required: Provide a brief description of the changes in this PR. --> - Fixed `foreach` state update and `foreach` bail in evented workflows - Fixed suspend-resume in evented-workflows legacy stream. ## Related issue(s) <!-- Required: Link to the issue(s) this PR addresses, e.g. with: Fixes mastra-ai#123. PRs without linked issues may be closed. --> ## Type of change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [x] Test update ## Checklist - [ ] I have linked the related issue(s) in the description above - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR fixes how workflows handle loops and pause/resume features. When a workflow loops through a list of items, it wasn't properly remembering changes made inside the loop, and the pause/resume feature had some debug code left in. The PR cleans up the tests to ensure they work correctly with these fixes. ## Summary This PR addresses three key issues in evented workflows: ### Core Fixes 1. **Fixed `foreach` state updates** - The `WorkflowEventProcessor` now properly persists and carries forward `__state` updates during `foreach` step handling. Previously, state mutations made inside a `foreach` body weren't being persisted for subsequent iterations. The fix writes the current state to storage under a special `stepId: '__state'` and includes it in the step results. 2. **Fixed suspend-resume in evented-workflows legacy stream** - Removed debugging code (a `console.dir()` statement) from the `EventedRun.resume` method that was left in the codebase. 3. **Fixed `foreach` bail behavior** - Addressed bail functionality in evented workflows (referenced in the PR description). ### Test Suite Improvements Refactored the evented workflow test suite (`evented-workflow.test.ts`) to use a single long-lived `Mastra` instance for all workflows. This ensures tests that call `workflow.createRun()` directly run against an engine with active event workers. The refactoring includes: - Module-level tracking of the registered Mastra instance and registry - Rebinding registry workflows back to the long-lived Mastra after each test - Suite lifecycle hooks to properly manage worker lifecycle and state cleanup - Updated imports to include the `WorkflowRegistry` type ### Changeset Added a patch-level changeset documenting these fixes for the `@mastra/core` package. [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16436) <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Description Add `@mastra/dsql` - a new storage provider for Amazon Aurora DSQL with IAM authentication. This package enables Mastra users to use Aurora DSQL's serverless, distributed PostgreSQL-compatible database as a storage backend for threads, messages, workflows, traces, and scores. ### Key Features - **Full storage interface implementation**: threads, messages, workflows, traces, spans, and evaluation scores - **IAM-based authentication**: Uses `@aws/aurora-dsql-node-postgres-connector` for automatic token generation (no database passwords) - **OCC retry logic**: Handles SQLSTATE `40001` (serialization failure) with exponential backoff and jitter - **Batch processing**: Splits large operations into batches of 3000 rows to respect Aurora DSQL's transaction limits - **Async index creation**: Uses `CREATE INDEX ASYNC` with `sys.wait_for_job()` for completion waiting - **JSONB workaround**: Stores JSON as `TEXT` columns with `::jsonb` casting at query time - **Automatic performance indexes**: Creates composite indexes during initialization for common query patterns - **Connection pool management**: Default 55-min max lifetime to handle Aurora DSQL's 60-minute connection limit ### Aurora DSQL-Specific Adaptations - No PostgreSQL extensions supported (pgvector, PostGIS, etc.) - No JSONB column types, foreign keys, triggers, or TRUNCATE - Only btree indexes supported - Single database (`postgres`) per cluster with schema-based isolation ### Package Structure ``` stores/dsql/ ├── src/ │ ├── index.ts # Main exports │ ├── shared/ # Config, retry, and batch utilities │ └── storage/ │ ├── index.ts # DSQLStore main class │ └── domains/ # Memory, observability, operations, scores, workflows ├── docs/ # Internal technical documentation └── package.json ``` ## Related Issue(s) mastra-ai#10929 ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [x] Test update ## Checklist - [x] I have made corresponding changes to the documentation (if applicable) - Added dsql.mdx with full API reference - [x] I have added tests that prove my fix is effective or that my feature works - Integration tests using `@internal/storage-test-utils` - DSQL-specific tests for IAM auth, batch limits, JSONB handling, etc. - Performance index tests <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Amazon Aurora DSQL storage provider with domain stores (memory, workflows, observability, scores), IAM-backed connections, pooling, OCC-aware retries, batching, and automatic performance index tooling. * **Documentation** * Expanded reference sidebar and added a comprehensive DSQL integration guide and README covering setup, usage, index management, and limitations. * **Tests** * Added unit, integration, performance suites and test utilities for DSQL behaviors and indexing. * **Chores** * Added package, build, lint, TypeScript, and Vitest configs for the new DSQL module. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Daniel Lew <danielshlomolew@gmail.com> Co-authored-by: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai> Co-authored-by: Daniel Lew <51924260+DanielSLew@users.noreply.github.com> Co-authored-by: Tyler Barnes <tylerdbarnes@gmail.com>
Adds an Integrations page for Mastra Code with a WezTerm/macOS guide for
hook-based notifications, click-to-focus behavior, and clearing stale
notifications when the terminal tab is focused manually.
The hook script includes short timeouts around external commands so it
does not block Mastra Code if WezTerm, osascript, sqlite3, or
terminal-notifier is slow.
After:
```json
{
"Stop": [
{
"type": "command",
"command": "bash \"$HOME/.mastracode/hooks/wezterm-mastracode-notify.sh\"",
"description": "Notify when Mastra Code goes idle in an inactive WezTerm pane"
}
]
}
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This PR adds a guide that helps you get notifications on your Mac when
Mastra Code is idle—and when you click the notification, it brings
Mastra Code back into focus in your terminal. It's like a reminder that
something finished, and clicking the reminder takes you right back to
it.
---
## Changes
### Documentation Updates
**New Integrations Guide for WezTerm/macOS Terminal Notifications**
- Added a new terminal notifications section to the Mastra Code
documentation index, linking to the integration guide
- Created a comprehensive integration guide
(`terminal-notifications.mdx`) that documents:
- A hook-based setup for sending clickable macOS notifications when
Mastra Code emits the `Stop` event in an inactive WezTerm pane
- Three supporting shell scripts:
- A script to focus the original WezTerm pane/tab and dismiss the active
notification
- A script to clear notifications when the pane becomes focused manually
- A main notification script that validates hook payloads, locates
pane/tab metadata via `wezterm` and `jq`, optionally fetches thread
titles via `sqlite3`, and displays notifications using
`terminal-notifier` (with callback to focus script) or `osascript` as
fallback
- Example `~/.mastracode/hooks.json` configuration entry for the `Stop`
hook event
- Instructions for reloading and testing the setup
- Notes on extending the integration to other hook events
The implementation uses short timeouts around external commands
(WezTerm, osascript, sqlite3, terminal-notifier) to prevent blocking
Mastra Code execution.
[](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16465)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Description <!-- Required: Provide a brief description of the changes in this PR. --> ## Related issue(s) <!-- Required: Link to the issue(s) this PR addresses, e.g. with: Fixes mastra-ai#123. PRs without linked issues may be closed. --> ## Type of change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [ ] I have linked the related issue(s) in the description above - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 When the playground builds its code, sometimes multiple copies of a library called react-query get bundled together by mistake, which breaks things. This PR tells the build system to only use one copy of react-query so everything works properly. ## Overview This PR fixes a Studio crash in the playground by deduplicating `@tanstack/react-query` in the Vite build configuration. The issue occurred when multiple React versions were installed, causing `@tanstack/react-query` to be duplicated in the bundle, which split the QueryClient context and resulted in "No QueryClient set" errors. ## Changes Made ### `.changeset/fix-playground-react-query-dedupe.md` - Added a changeset documenting a patch version bump for the `@internal/playground` package - Documents the fix for the Studio crash caused by duplicated `@tanstack/react-query` ### `packages/playground/vite.config.ts` - Updated the Vite `resolve.dedupe` configuration to include `@tanstack/react-query` - Ensures only one instance of `@tanstack/react-query` is included in the build output ## Impact - Resolves the "No QueryClient set" error in the playground when multiple React versions are present - Maintains consistent QueryClient context across the entire playground bundle [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16469) <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…mastra-ai#16433) ## Summary - **playground-ui (minor):** Added `pill-ghost` Tabs variant + `sticky` TabList prop, `variant` prop on Combobox (`default`/`ghost`/`link`), tighter `EntityHeader` (title + children share row), orientation-aware `ScrollArea` overflow, redesigned `PanelSeparator` (pill-shaped handle). Removed `Threads`/`ThreadList`/`ThreadItem`/`ThreadLink`/`ThreadDeleteButton` exports (no external usage). - **playground (patch):** New local `thread-list` component replacing removed `Threads` exports. Refreshed agent header / information / playground view / version bar / page tabs and workflow information / run list with refined layouts using DS primitives. Chat composer gets subtle send animation and tuned border. ## Changesets - `pretty-bananas-clean.md` — `@mastra/playground-ui` minor - `kind-singers-type.md` — `mastra` patch ## Test plan - [ ] `pnpm --filter @mastra/playground-ui build` - [ ] `pnpm --filter mastra build` - [ ] Storybook: verify `Tabs` (`pill-ghost`), `Combobox` (3 variants), `EntityHeader`, `ScrollArea` (vertical + horizontal), `PanelSeparator` hover/active - [ ] Studio: chat threads list, new chat link, delete flow - [ ] Studio: workflow information panel (sticky header + tabs, run list) - [ ] Studio: agent header / playground / version bar - [ ] Studio: composer send animation triggers on submit - [ ] `pnpm --filter playground exec playwright test e2e/tests/agents/\$agentId/stream.spec.ts` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 (Explain Like I'm 5) This PR cleans up the shared UI toolkit, moves the chat/thread list UI into the playground app so it can evolve independently, adds a few nicer visual options (new tab and combobox variants), and makes the chat composer show a subtle send animation so interactions feel snappier. --- ## Changes Summary ### playground-ui (minor) - UI features and fixes: - Tabs: added `pill-ghost` variant; `TabList` gains optional `sticky` prop. - Combobox: introduced `variant` prop (`default | ghost | link`) and refactored trigger styles into base + variant classes. - EntityHeader: denser layout so title and children share a single row; reduced padding. - ScrollArea: orientation-aware overflow behavior and content min-size fixes to enforce a single scroll axis. - PanelSeparator: redesigned indicator to a pill-shaped handle with enhanced hover/active/focus visuals. - Removals: - Removed thread-related exports and stories from the DS: `Threads`, `ThreadList`, `ThreadItem`, `ThreadLink`, `ThreadDeleteButton`, and `threads.stories.tsx`. - Stopped re-exporting Threads from package entrypoint. ### playground (patch) - Thread UI migration: - Added local `thread-list` primitives and re-export: `ThreadList`, `ThreadListNewItem`, `ThreadListEmpty`, `ThreadListItems`, `ThreadListItem`, `ThreadListSeparator`. - Replaced all usages of the removed playground-ui Threads components (chat threads, workflow run list) with the new local primitives; delete actions wired via `onDelete` only when allowed. - `ThreadList` nav now accepts an `aria-label` (defaults to "Threads"); workflow-run-list passes "Workflow runs". - Guarded workflow-run-list against reading `run.snapshot.status`/`timestamp` when `snapshot` may be null. - Component & layout updates using DS primitives: - Agent header: `AgentCombobox` rendered with `variant="ghost"` and `size="sm"`; `AgentCombobox` now accepts a `size` prop. - AgentInformation & WorkflowInformation: tabbed UIs wrapped in `ScrollArea` with sticky headers for consistent scrolling. - Agent playground view: replaced `Panel` with `CollapsiblePanel` for left/right panes and adjusted sizing/collapse behavior. - Agent page tabs switched to `pill-ghost` variant. - Workflow run list and related UIs refactored to `thread-list` primitives; timestamp/status rendering tightened to avoid null reads. - ZoomSlider and other panels updated to use shared Panel/Button styles. - Chat composer and messages: - Added composer send animation: new CSS keyframes and `.composer-sending` class; composer triggers a send-pulse overlay on submit. - Tweaked user message bubble sizing and composer border styling. - Tests & stories: - Added Vitest/jsdom tests for ScrollArea orientation/min-size behavior. - Storybook: added `PillGhostVariant` for Tabs; removed Threads stories. - Playwright e2e: expectation updated for thread-list item count after reload. --- ## API / Export surface - Added: - `ComboboxVariant` type and functional `variant` prop (`default | ghost | link`) with trigger style mapping. - `TabListProps.sticky?: boolean`. - `thread-list` primitives exported from the playground package. - Removed: - From `@mastra/playground-ui`: `Threads`, `ThreadList`, `ThreadItem`, `ThreadLink`, `ThreadDeleteButton` (and related stories). - No other public prop/type signatures changed across playground components (most changes are internal/layout/composition). --- ## Changesets - `@mastra/playground-ui` bumped as minor (pretty-bananas-clean.md). - `mastra` bumped as patch (kind-singers-type.md). --- ## Test Plan (high level) - Build `@mastra/playground-ui` and `mastra`. - Storybook: verify Tabs (`pill-ghost`), Combobox variants, EntityHeader, ScrollArea (vertical/horizontal/both), PanelSeparator hover/active. - Studio: chat threads list, new chat link, delete flow; workflow information panel (sticky header + tabs, run list); agent header/playground/version bar; composer send animation on submit. - Playwright e2e: pnpm --filter playground exec playwright test e2e/tests/agents/\$agentId/stream.spec.ts. [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16433) <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Greg Lobinski <32480082+greglobinski@users.noreply.github.com>
…astra-ai#14717) ## Problem When using `agent.stream()` with `structuredOutput`, the message persisted to thread history had its text set to `"[object Object]\n[object Object]\n..."` instead of the actual response content. Fixes mastra-ai#14659 ## Root cause In `packages/core/src/agent/workflows/prepare-stream/map-results-step.ts`, the stream path's `onFinish` callback computed `outputText` as: ```ts messageList.get.all.core().map(m => m.content).join('\n') ``` `m.content` is an object (not a string), so `.join()` serialized it as `"[object Object]\n..."` — silently corrupting thread history for every `stream()` + `structuredOutput` call. ## Fix Use `payload.text` for plain output and `JSON.stringify(payload.object)` for structured output — matching the `generate` path's existing behavior. ## How to test ```ts const agent = new Agent({ model, structuredOutput: z.object({ answer: z.string() }) }) const stream = await agent.stream('What is 2+2?', { threadId, resourceId }) await stream.consumeStream() // Thread message text should be JSON, not '[object Object]' const messages = await memory.getMessages({ threadId }) expect(messages.at(-1)?.content).not.toContain('[object Object]') ``` All existing tests pass. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed streaming agent persistence so assistant messages store readable text from structured outputs instead of serialized object artifacts, improving message consistency and reliability. * **Tests** * Added a regression test validating streaming with structured output and memory persistence to prevent future regressions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ward Peeters <ward@coding-tech.com> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com>
…2860) ## Description Refactored the `executeForeach` function to use `fastq` (a callback-based queue library) instead of the previous batch-based approach with `Promise.all`. This change improves concurrency handling by starting the next item as soon as any worker slot frees up, rather than waiting for an entire batch to complete. ### Key Changes: - Added `fastq` dependency (v1.19.1) to package.json - Replaced the batch-based loop (`Promise.all` on slices) with a `fastq` queue that maintains true fluid concurrency - Refactored item processing into a worker function that handles individual tasks - Improved error and suspension handling to stop processing remaining queued items when an error or suspension occurs - Maintained backward compatibility with resume logic and suspend/error behavior ### Benefits: - **Better resource utilization**: Items start processing immediately when a worker becomes available, rather than waiting for batch boundaries - **Cleaner code**: The queue-based approach is more intuitive for concurrent task processing - **Same semantics**: Error handling, suspension, and resume behavior remain unchanged ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [x] Code refactoring - [x] Performance improvement - [ ] Test update ## Checklist - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works https://claude.ai/code/session_01HRDs2f9fzXwwSruxV2jvwC <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Reworked foreach execution to a queue-driven, worker-based concurrency model for more reliable per-item processing, clearer error and suspension handling, safer resume behavior, and deterministic finalization. * **Chores** * Added a new runtime dependency to support the updated concurrency mechanism. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Fixes mastra-ai#9061 --------- Co-authored-by: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>
## Description <!-- Required: Provide a brief description of the changes in this PR. --> ## Related issue(s) <!-- Required: Link to the issue(s) this PR addresses, e.g. with: Fixes mastra-ai#123. PRs without linked issues may be closed. --> Suspend and resume now works reliably for evented workflows that use parallel steps, `.branch()`, `dountil`/`dowhile` loops, and nested workflows — previously it only held up for simple linear flows. **Parallel & `.branch()` steps** — when more than one branch suspends at the same time (e.g. each branch waits on its own approval), every suspended branch can now be resumed, the workflow stays suspended until all of them have been resumed, and the branch outputs are merged correctly. Before, only the last branch to suspend was resumable, and resuming one branch could prematurely complete the run. **`dountil` / `dowhile` loops** — a loop body that calls `suspend()` now suspends the workflow instead of crashing the run. And after a resume, subsequent loop iterations run fresh instead of re-receiving the resume data — which previously made loops either run forever or skip their own suspend logic. **Nested workflows** — resuming a suspended step inside a nested workflow now gives it the correct input (the output of the step right before it, not the nested workflow's own input), so it produces correct results, even when workflows are nested several levels deep. The suspended-step path returned in a workflow result is also correct now, so you can pass it straight back into `resume({ step })`. ## Type of change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [x] Test update ## Checklist - [ ] I have linked the related issue(s) in the description above - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR fixes pausing and resuming for workflows so they reliably continue from where they left off even when running parallel branches, loops, or nested workflows. Previously, complex flows could crash, skip suspend logic, or resume with incorrect data. ## Changes ### Reliability improvements to suspend/resume for evented workflows - Parallel & .branch(): - Multiple concurrently suspended branches are now all resumable. - Workflow stays suspended until every suspended branch resumes. - Branch outputs are merged correctly; resuming one branch no longer can prematurely complete the run. - Centralized aggregation logic prevents suspend/resume races. - dountil / dowhile loops: - Suspending inside a loop body no longer crashes the run. - After resume, subsequent iterations run with fresh state (resumeData cleared) so iterations don't reuse stale resume data or enter infinite loops. - Nested workflows: - Resuming a suspended step inside nested workflows now receives the correct input (the previous step's output). - The suspended-step path included in workflow results is corrected so it can be passed directly to resume({ step }) across nesting levels. - Nested resume publishes use a constructed prevResult derived from the nested workflow snapshot when appropriate. ### Implementation details / touched files - packages/core/src/workflows/evented/workflow-event-processor/index.ts - Added protected aggregateBranchResults(...) to merge branch outputs and handle combined suspend/resume behavior. - processWorkflowSuspend now prepends inner step IDs into __workflow_meta.path when propagating nested suspends. - processWorkflowStepRun constructs nestedPrevResult for resumed inner steps and handles loop-step suspended outcomes by early-publishing workflow.step.end. - processWorkflowStepEnd emits workflow-step-suspended watch event and delegates branch aggregation to aggregateBranchResults. - packages/core/src/workflows/evented/workflow-event-processor/loop.ts - Loop control now builds reusable loopAgainData/loopEndData payloads and clears resumeData/resumeSteps appropriately so resumed iterations are treated as fresh runs. - packages/core/src/workflows/evented/execution-engine.ts - Cleans stepResults to drop entries with status 'skipped' so internal bookkeeping doesn't leak into user-facing steps output. - packages/core/src/workflows/evented/evented-workflow.test.ts - Enabled previously skipped tests (cleared skipTests) except the restart domain; resumeWorkflow helper now forwards forEachIndex into run.resume(...). - .changeset/ten-experts-check.md - Patch bump for @mastra/core documenting these reliability fixes. Type: bug fix (with test updates) [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16476) <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Adds a list-mode switcher to **Observability → Traces** that toggles
between **Top-level traces only** (existing behavior, one row per
top-level run) and **All traces, nested too** (one row per anchor span —
every agent / workflow / tool / processor / scorer / RAG invocation,
including ones nested inside other runs).
- Reuses the existing trace list/timeline/span components — the detail
panel renders a branch subtree where the anchor span has a non-null
`parentSpanId` (the parent lives outside the returned spans).
- Frontend-only. Backend `listBranches` / `getBranch` endpoints already
exist in `client-js` and `@mastra/server`.
## Notable additions
- **`useBranch({ traceId, spanId, depth? })`** — wraps
`client.getBranch` for the per-branch subtree fetch.
- **`useTraceOrBranchSpans({ traceId, anchorSpanId, listMode })`** —
umbrella hook the page uses; routes between trace and branch data
sources based on the active mode.
- **`anchorSpanId` URL param** — branch identity. Kept stable while
intra-panel span navigation changes `spanId`, so the side span panel can
move around the subtree without re-fetching it.
- **Optional props** on existing exports (`TraceDataPanelView` →
`anchorSpanId`, `SpanDataPanelView` → `isAnchor`, `TracesListView` →
`featuredSpanId`, `formatHierarchicalSpans` → `anchorSpanId`) so a
subtree whose top span has a real parent renders correctly. All default
to the existing trace-mode behavior.
- **Virtualizer reset on mode toggle** via `key={url.listMode}` on
`<TracesListView>` — the virtualizer caches measurements from the
previous mode's row count and `isLoading` doesn't flash when both modes
are cached, so a fresh mount is the cleanest fix.
## Test plan
- [ ] `pnpm --filter @mastra/playground-ui vitest run
src/domains/traces` — 30 unit tests (including new
`format-hierarchical-spans` coverage for anchor-as-root and the existing
`useTraces` logic).
- [ ] `pnpm --filter @internal/playground test:e2e --
e2e/tests/observability/list-mode-switcher.spec.ts` — 6 behavior tests
covering default mode, toggle to branches, toggle back, URL clearing on
mode switch, branch detail rendering, and intra-panel span nav staying
on the same subtree.
- [ ] Manual in browser:
- [ ] Default load on `/observability` is "Top-level traces only" with
`/api/observability/traces` called.
- [ ] Switching to "All traces, nested too" surfaces nested rows, URL
gains `?listMode=branches`.
- [ ] Clicking a branch row opens the subtree detail (anchor +
descendants).
- [ ] Prev/next on the trace panel steps through branch rows (URL
updates `traceId` + `anchorSpanId`).
- [ ] Prev/next on the side span panel walks spans **within** the
current subtree (URL `spanId` changes; `anchorSpanId` stays; no
`getBranch` refetch).
- [ ] Switching back to "Top-level traces only" drops the nested rows
and clears anchor/selection params.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This PR adds a toggle to Observability → Traces so you can switch
between viewing only top-level runs (default) or every invocation
including nested calls; in the nested ("branches") mode each invocation
is a row and clicking a row opens a detail panel focused on that
invocation's subtree (the anchor span).
---
## Overview
Adds a list-mode switcher to Observability → Traces that toggles
between:
- "Top-level traces only" (default): one row per top-level run.
- "All traces, nested too" (branches): one row per invocation
(agents/workflows/tools/processors/scorers/RAG invocations), making
nested spans individual rows and enabling branch-focused detail panels.
Frontend-only changes that reuse existing list/timeline/span components
with opt-in props; backend endpoints (listBranches / getBranch) already
exist in client-js and @mastra/server.
---
## Key Changes
Hooks
- useBranch({ traceId, spanId, depth? }) — React Query wrapper around
client.getBranch to fetch a branch subtree; uses long staleTime once
returned spans have ended.
- useTraceOrBranchSpans({ traceId, anchorSpanId, listMode, depth }) —
chooses trace vs branch data source based on listMode and returns spans
+ loading/error state.
Components / API
- TraceDataPanelView: optional anchorSpanId prop to treat a span as the
displayed root for timeline and metadata.
- SpanDataPanelView: optional isAnchor prop to control anchor/root-only
trace-context metadata rendering (falls back to parentSpanId == null).
- TracesListView: supports featuredSpanId; rows now carry optional
spanId and virtualized item keys use `${traceId}:${spanId ?? ''}` so
branch rows with the same traceId are distinct.
- formatHierarchicalSpans(spans, anchorSpanId?): builds hierarchical
trees; when anchorSpanId is provided the anchor is treated as the
displayed root even if its parent is outside the provided set; orphan
spans (missing parent) surface as roots; the displayed root's endTime is
extended to the latest endedAt among its subtree so latency reflects the
full branch.
- TracesListModeToggle component: toolbar dropdown to switch between
traces and branches.
URL, state & navigation
- New URL param constant TRACE_ANCHOR_SPAN_ID_PARAM ('anchorSpanId') for
a branch-mode anchor that remains stable while intra-panel navigation
updates spanId.
- useTraceUrlState: adds anchorSpanIdParam, handleListModeChange (clears
selection on mode change), and expands handleTraceClick to (traceId,
spanId?, anchorSpanId?).
- useTraceListNavigation: branch-aware navigation using traceId + spanId
identity; only forwards spanId when in branches mode.
- Traces page (index): integrates the toggle, passes
anchorSpanId/featuredSpanId into list and panel logic; remounts
TracesListView on mode changes via key={url.listMode} to reset the
virtualizer; "Evaluate Trace" jumps to the anchor in branches mode.
Behavior
- Detail panel renders a branch subtree when the anchor span has a
non-null parentSpanId (the parent can live outside the fetched spans).
- Intra-panel navigation updates only spanId while preserving
anchorSpanId to avoid refetching the subtree.
- Toggling modes clears traceId/spanId/anchorSpanId to avoid mismatched
context.
- Virtualizer reset on mode toggle prevents stale measurements and
loading flashes.
---
## Tests
- ~30 unit tests for traces domain (including formatHierarchicalSpans
and branches-related behavior).
- 6 Playwright E2E specs covering default mode, toggling to branches and
back, URL param behavior (listMode, anchorSpanId), branch detail
rendering for anchors with outside parents, intra-panel navigation
staying within subtree, and selection clearing on mode switches.
---
## Notable Details
- Orphan spans whose parent isn't in the fetched set are surfaced as
roots to represent branch-subtree boundaries correctly.
- The displayed root/anchor endTime is extended to the subtree's latest
endedAt so timeline and latency reflect the full branch.
- Barrel exports updated to include new hooks and TracesListModeToggle.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- **chore(ci): rewrite uniet/e2e tests** - **remove cache from publish** - **cleanup prebuild** ## Description <!-- Required: Provide a brief description of the changes in this PR. --> ## Related issue(s) <!-- Required: Link to the issue(s) this PR addresses, e.g. with: Fixes mastra-ai#123. PRs without linked issues may be closed. --> ## Type of change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [ ] I have linked the related issue(s) in the description above - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 (Explain Like I'm 5) This PR tidies up CI: it stops using a package-manager cache when publishing, makes the prebuild step more secure and conditional around the Turbo token, and adds a new reusable, sharded test workflow so unit and E2E tests run in parallel and produce consistent reports. --- ## Changes Overview ### `.github/workflows/npm-publish.yml` - Disable package-manager cache for `actions/setup-node@v5` by adding `package-manager-cache: false` to the Node setup in prerelease/stable/enter_prerelease/snapshot jobs. - Effect: prevents actions/setup-node from using pnpm cache during publish flows. Lines changed: +4/-0 --- ### `.github/workflows/prebuild.yml` - Make `env.TURBO_CACHE` conditional: `local:rw` when `secrets.TURBO_TOKEN` is empty, otherwise `remote:rw`. - Reduce job permissions to `contents: read` (remove prior PR/status writes). - Replace custom PR status step with local `./.github/actions/setup-pnpm-node` action for Node/pnpm setup. - Conditionally cache `.turbo/cache` with `actions/cache@v4` only when `TURBO_TOKEN` is empty. - Keep the changes-detection gating (`has_code`) and call the `test-suite` reusable workflow; when invoking `test-suite`, explicitly set `permissions: actions: read, contents: read` and pass `TURBO_TOKEN` and `TURBO_TEAM` secrets. Lines changed: +26/-13 --- ### `.github/workflows/test-suite.yml` - Add a new reusable workflow (`workflow_call`) accepting `head_sha` and `base_ref` inputs and optional `TURBO_TOKEN`/`TURBO_TEAM` secrets. - Jobs: - `unit-test`: 4-shard matrix for `unit:*` and `typecheck:*` Vitest runs; builds repo (excludes examples/docs/explorations); produces blob reports at `.vitest-reports/blob-unit-<shard>.json` and uploads short-retention artifacts per shard. - `e2e-test`: matrix over `packages/*`, normalizes package names to `project_id`, runs per-package E2E Vitest (`e2e:<project>`), writes `.vitest-reports/blob-e2e-<project_id>.json`, and uploads short-retention artifacts. - `merge-reports`: runs after test jobs, downloads all `vitest-blob-*` artifacts with `merge-multiple: true` and runs `pnpm vitest --merge-reports` to produce consolidated output and GitHub Actions reporting. - Applies the same conditional TURBO_CACHE pattern and conditional `.turbo/cache` caching when `TURBO_TOKEN` is empty. - Sets larger Node memory for unit and e2e workflows. Lines changed: +182/-0 --- ### `.github/workflows/vitest-changed.yml` - No observable changes in the provided diff snapshot; the supplied diff lacked new hunk content so effective modifications could not be determined from the input. Lines changed: +0/-656 (diff-only snapshot) --- ## Impact & Review Notes - Caching: publish now avoids package-manager cache; prebuild `.turbo/cache` is only used locally when `TURBO_TOKEN` is absent — reviewers should confirm expected cache behavior with and without the Turbo token/secret. - Permissions: prebuild permissions are tightened to read-only for contents; confirm no downstream steps relied on prior write permissions (PR/status updates). - Tests: new reusable test-suite introduces sharded/unit and per-package E2E runs, changes artifact names/retention, and centralizes report merging — verify artifact retention/consumption and naming expectations. - The diff for `vitest-changed.yml` in the provided input was inconclusive; if that file was intended to be removed or modified, please confirm with full diff or repository state. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…stra-ai#16484) `@mastra/koa@1.5.0` introduced a dispatcher-reuse optimization that unconditionally reads `app.middleware.length` in `getRouteDispatcherGroup`. Subclasses that forward a non-Koa app-like object (e.g. a `koa-router`, a mounted sub-app, or a custom wrapper) to `super.registerRoute(app, route, opts)` hit `undefined.length` and crash at `MastraServer.init()` with `TypeError: Cannot read properties of undefined (reading 'length')`. This guards reuse on `Array.isArray(app.middleware)` and falls back to registering a fresh dispatcher per route via `app.use` when the array isn't there — the same per-route behavior the adapter had before 1.5.0. Real Koa apps keep the optimization unchanged. Before: ```ts class CustomKoaMastraServer extends MastraServer { async registerCustomApiRoutes() { for (const route of this.mastra.getServer()?.apiRoutes ?? []) { await super.registerRoute(this.router as any, route, { prefix: this.prefix }); // 💥 TypeError: Cannot read properties of undefined (reading 'length') } } } ``` After: the same subclass initializes cleanly and routes register on the forwarded target via `.use()`. Covered by four new tests in `Route dispatcher > non-Koa app-like targets` — each one was verified to fail against the unguarded implementation and pass with the fix. Full koa adapter suite: 2,188/2,188 passing. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 The PR fixes a crash that happens when Koa server code tries to reuse optimization shortcuts for router-like objects that don't have all the expected properties. By checking if the property exists before using it, the code now gracefully falls back to the slower (but safe) approach for these unusual objects, while keeping the optimization for normal Koa apps. ## Summary This PR fixes a `TypeError` in `@mastra/koa@1.5.0` that occurs during `MastraServer.init()` when a subclass forwards a non-Koa app-like object (such as a koa-router instance, mounted sub-app, or custom wrapper) to the `registerRoute` method. The dispatcher-reuse optimization introduced in 1.5.0 unconditionally accessed `app.middleware.length`, which failed when `app.middleware` was undefined or not an array. ## Changes **server-adapters/koa/src/index.ts** - Updated `getRouteDispatcherGroup()` to guard the dispatcher-reuse optimization by checking `Array.isArray(app.middleware)` before attempting to reuse an existing dispatcher group - Falls back to registering a fresh dispatcher per route via `app.use()` when the optimization is unavailable, matching the pre-1.5.0 behavior - Real Koa apps with a proper `middleware` array retain the optimization **server-adapters/koa/src/__tests__/koa-adapter.test.ts** - Added four new test cases under "Route dispatcher > non-Koa app-like targets" covering: - No crash when `middleware` is missing - Correct handling when `middleware` exists but is not an array - Fresh dispatcher creation per route when reuse is impossible - End-to-end request handling with router-like targets mounted in a real Koa app **.changeset/ten-hats-slide.md** - Documents the patch-level fix with an illustrative TypeScript example demonstrating the previous crash and the corrected behavior ## Verification The full koa adapter test suite reports 2,188/2,188 tests passing. All four new tests were verified to fail on the unguarded implementation and pass with the fix applied. [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16484) <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
) ## Summary Wires MastraCode follow-up input through Agent signals so active chats can accept new user context without waiting for the current run to finish. Active follow-ups render as pending until the stream echoes the stable signal id back. When the echo arrives, the pending placeholder is replaced with the streamed user message and the current assistant stream is split so subsequent output renders below that user message. Idle input uses the same signal path to start the thread. ## Stack Previous PR: mastra-ai#16438 — Route system reminders through Agent signals This is PR 3 of the Agent signals stack: 1. mastra-ai#16229 — Core Agent signal runtime, server routes, and client-js API 2. mastra-ai#16438 — Route system reminders through Agent signals 3. mastra-ai#16231 — Use Agent signals for MastraCode follow-up chat 4. mastra-ai#16338 — Use Agent signals for Studio/playground follow-up chat ## What changed - Sends MastraCode follow-up messages through `harness.sendSignal()`. - Tracks pending signal messages by signal id and clears them when the stream echo arrives. - Treats echoed signal user messages as stream boundaries so assistant output after the echo renders below the user message. - Keeps a single thread subscription as the stream owner to avoid double rendering. - Preserves `/new`, image follow-ups, slash-command behavior, and tool approval/resume output on the signal path. ## Test plan - `pnpm --filter ./packages/cli test src/mastra-tui-queueing.test.ts src/render-messages.test.ts src/message.test.ts --bail 1 --reporter=dot` - `pnpm --filter ./packages/cli check` - `pnpm --filter ./packages/cli build:lib` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 You can type new messages while the assistant is still talking; they show up as "pending" immediately and become real messages once the system confirms them, and the assistant's reply continues after those confirmed messages. ## Overview This PR routes MastraCode follow-up input through the Agent signal path so active chats can accept new user context without waiting for the current run to finish. Follow-ups render optimistically as pending until a stable signal-id echo arrives; when echoed, the pending placeholder is replaced by the confirmed user message and the assistant's stream is split so subsequent assistant output renders after that message. Idle input uses the same signal path to start threads. Existing behaviors—/new, image follow-ups, slash commands, and tool approval/resume—are preserved. A harness fix ensures idle signal acceptance waits for the subscription stream's terminal chunk before emitting synthetic end events. ## Core changes - packages/core/src/harness/harness.ts - Introduces per-(agent,resource,thread) agent-thread subscriptions and a subscription-driven stream processor. - Adds sendSignal(...) (returns {id, type, accepted: Promise<...>}) and isCurrentThreadStreamActive(); getCurrentRunId() is subscription-aware. - sendMessage delegates to sendSignal; subscription lifecycle cleaned up on thread/resource changes; abort aborts active subscriptions. - Stream chunk processing reworked (processSubscribedThreadStream / processStreamChunk / finishStreamState). - Tool approval/decline/resume flow updated to await agent methods and route resumed streams through the subscription processor. - Message merging & boundaries - MessageMerger prevents merging across messages marked with mastra.responseBoundary. - MessageList adds markResponseMessageBoundary(...) and normalizes createdAt for signal/input messages. - Agentic execution marks response boundaries when interjections are enqueued. - Tests - New/extended harness and agent signal tests validate signal lifecycles, echoed data-user-message handling, idle vs active signal behavior, interjections, persisted ordering when draining signals into active runs, and waiting for subscription terminal chunks. ## MastraCode TUI changes - Pending user-message lifecycle and rendering (mastracode/src/tui/render-messages.ts, components/user-message.ts) - Adds helpers: addPendingUserMessage, confirmPendingUserMessage, removePendingUserMessage, clearPendingUserMessages. - UserMessageComponent accepts a pending option (dimmed styling); PendingUserMessage lifecycle reconciles echoed messages by id or normalized text and deduplicates echoed slash-commands/images. - During active streaming, incoming user messages are treated as follow-ups and reconciled against pending entries to avoid duplicates. - State and pruning (mastracode/src/tui/state.ts, prune-chat.ts) - TUIState extended with pendingSignalMessageComponentsById: Map<string, PendingSignalMessage>. - pruneChatContainer removes pending entries when their components are pruned. - Input flow, optimistic signals & harness integration (mastracode/src/tui/mastra-tui.ts) - Submit flow: render optimistic user message, run UserPrompt hooks, remove if blocked, then sendOptimisticSignal(...) to remap optimistic IDs to real harness signal IDs. - Helpers added for optimistic lifecycle, pending-thread creation, and handling sendSignal accepted/rejected outcomes (replace pending or remove optimistic). - addChildBeforeFollowUps updated to insert new components before the earliest pinned component among follow-ups and pending-signal components. - Keyboard and shortcuts (components/custom-editor.ts, setup.ts, help-overlay.ts) - Adds queueFollowUp action and Ctrl+F shortcut to explicitly queue follow-ups while a run is active. - Enter consistently triggers editor.onSubmit (completing autocomplete first); Ctrl+F is the explicit "queue follow-up" during runs. - Help text split to show "Send message" and "Queue follow-up (Ctrl+F)" separately. - Handlers and lifecycle (tui/handlers/message.ts, tui/handlers/agent-lifecycle.ts) - Echoed signal user messages are treated as stream boundaries so assistant output after the echo renders below the user message. - handleAgentAborted / handleAgentError now clear pending user messages during cleanup. - Goal continuation now sends a system-reminder via harness.sendSignal(...) instead of firing a message. ## Tests updated Widespread test additions/updates across MastraCode and core: - Mastracode TUI tests: queueing, render-messages, keyboard shortcuts, command-dispatch, prune-chat, custom-editor, goal flows, message handlers. - Core tests: harness signal-message lifecycle, signal-history subscription behavior, agent signals interjection and persistence tests. Coverage focuses on pending lifecycle, optimistic→pending remap, deduplication of echoed slash commands/images, idle vs active signal handling, assistant insertion after echoed user messages, and waiting for subscription terminal chunks. ## Changesets & release notes - Core: bumps and documents Harness thread subscriptions, stable signal echoes, idle signal starts that allow optimistic rendering, and waiting for subscription terminal chunks before emitting end events. - Mastracode: documents signal-based follow-up support, pending UI lifecycle, single subscription ownership to avoid duplicate rendering, new keyboard shortcut for queueing follow-ups, and goal-reminder signal behavior. [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16231) <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
## Summary Adds two local workflow skills for improving PR review quality: - `pr-splitter` helps break large, tangled PRs into smaller reviewable PRs while tracking extraction and drift in a local scratchpad. - `pr-explainer` helps generate approachable, self-contained HTML review aids in `.pr-review/` that explain what changed, why it matters, how it works, and how it was verified. - Adds `.pr-review/` to `.gitignore` so generated local review pages are not committed by default. ## Test plan - Read both skill files to verify trigger descriptions and workflow guidance. - Ran `git diff --cached --check` before committing to verify the patch has no whitespace errors. No package changes, so no changeset was added. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR adds two simple helpers to make code reviews easier: one helps split big, messy changes into bite-sized PRs, and the other generates local HTML review pages that explain what changed and how it was tested. It also tells Git to ignore the folder where those HTML review pages are written. ## Changes **Added** - `.claude/skills/pr-explainer/SKILL.md` — Workflow for creating self-contained HTML "PR explainer" pages under `.pr-review/`. Covers git inspection commands, recommended narrative/order and HTML section structure, diagram guidance, focused diff-snippet formatting, verification/proof requirements (example commands), a final checklist, and expected default outputs (path, coverage, sections, evidence, and untracked status). - `.claude/skills/pr-splitter/SKILL.md` — Workflow for splitting large, tangled PRs into multiple smaller PRs. Includes snapshotting the original branch, inventorying changes by review unit, a local uncommitted scratchpad template, strategies (stacked vs parallel, foundation + follow-ups), safe extraction techniques (path-level and hunk-level restore), independent verification steps, drift management (rebasing dependent PRs, recording differences), a reviewer-facing PR description template, common failure modes, and a required checklist. **Modified** - `.gitignore` — Added `.pr-review/` so generated local review pages are not committed by default. ## Review Effort Low to Medium — documentation-only changes. No code, dependency, or changeset modifications. Total added documentation ≈ 260 lines across the two skill files plus one .gitignore entry. ## Test Plan Reviewer read both SKILL.md files to verify trigger descriptions and workflow guidance; author ran `git diff --cached --check` before committing to confirm no whitespace errors. [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16456) <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
mastra-ai#16493) ## Summary - Flip the Observability Traces default from top-level traces to **branches** (all traces, nested too). With no `listMode` in the URL, the page now fetches `/api/observability/branches`. - Remove the list-mode toggle from the local studio toolbar. The component file is kept in `playground-ui` for now in case we want to surface it elsewhere. - URL contract still recognizes `?listMode=traces` for the top-level-only view; `?listMode=branches` continues to parse but is now redundant. ## Notes - Changes live in [use-trace-url-state.tsx](packages/playground-ui/src/domains/traces/hooks/use-trace-url-state.tsx) (default + toggle handler) and [use-traces.tsx](packages/playground-ui/src/domains/traces/hooks/use-traces.tsx) (defensive default). The toggle render was removed from [packages/playground/src/pages/traces/index.tsx](packages/playground/src/pages/traces/index.tsx). - Deleted `packages/playground/e2e/tests/observability/list-mode-switcher.spec.ts` — every test in there asserted toggle behavior or the old default. Two URL-driven tests (branch-detail rendering and intra-panel nav) lived in the same file and went with it; happy to reinstate either as a new spec if we want that coverage. ## Test plan - [ ] `/observability` with a clean URL renders branch rows (nested invocations visible) and the backend call is `/api/observability/branches` - [ ] `/observability?listMode=traces` still renders top-level traces only and hits `/api/observability/traces` - [ ] Toolbar no longer shows the "Top-level traces only / All traces, nested too" dropdown - [ ] Typecheck passes for `@mastra/playground-ui` and `@internal/playground` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR makes the Observability page show all traces (including nested ones) by default instead of only top-level traces. The toolbar dropdown for switching modes was removed because the new default covers that view; you can still force the old top-level-only view via the URL. ## Changes ### Default Observability Mode Changed to Branches - `/observability` now defaults to "branches" mode (shows nested traces). Previously the default was "traces" (top-level only). - `?listMode=traces` still forces the top-level view; `?listMode=branches` is still parsed but now redundant. ### Code Changes - packages/playground-ui/src/domains/traces/hooks/use-trace-url-state.tsx - Treats `branches` as the default `listMode` when the TRACE_LIST_MODE_PARAM is absent/invalid. - `handleListModeChange` deletes the URL param when switching to `branches` (default) and sets it when switching to other modes. - packages/playground-ui/src/domains/traces/hooks/use-traces.tsx - `fetchTracesFn` and the exported `useTraces` hook default `listMode` to `'branches'` instead of `'traces'`. ### UI Removal - packages/playground/src/pages/traces/index.tsx - Removed rendering/import of `TracesListModeToggle` from the Traces page toolbar. ### Tests - Deleted packages/playground/e2e/tests/observability/list-mode-switcher.spec.ts, which contained tests asserting the previous toggle/default behavior and endpoint selection (`/traces` vs `/branches`). ### Other - Added a changeset for `@mastra/playground-ui` documenting this behavioral change (patch). <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ai#16495) ## Description The `minimumReleaseAge: 1440` setting added to `pnpm-workspace.yaml` in mastra-ai#16462 (as a supply-chain defense ahead of the pnpm v11 default) also applies to our **own** snapshot/canary publishes. E2E flows that publish a temporary `0.0.0-…-snapshot` version and then immediately try to install it fail with: ``` ERR_PNPM_NO_MATURE_MATCHING_VERSION No matching version found for @mastra/loggers@0.0.0-…-snapshot The package was released just now and you have a minimumReleaseAge of 1440 minutes set. ``` Affected workflows on main: - `E2E Tests / create-mastra` (pnpm dlx create-mastra@…-snapshot) - `E2E Tests / no-bundling` - `E2E Tests / monorepo` - `E2E Tests / deployers` ## Fix Add `minimumReleaseAgeExclude` listing first-party package patterns. The supply-chain defense remains in effect for all third-party dependencies; only our own packages bypass the 1-day wait. ```yaml minimumReleaseAgeExclude: - '@mastra/*' - '@internal/*' - 'mastra' - 'create-mastra' ``` Setting reference: https://pnpm.io/settings#minimumreleaseageexclude (available since pnpm 10.10). ## Test plan - CI `E2E Tests` job should no longer fail with `ERR_PNPM_NO_MATURE_MATCHING_VERSION` for `@mastra/*` / `@internal/*` / `mastra` / `create-mastra` snapshot versions. - Third-party packages still gated by the 1-day `minimumReleaseAge`. ## Type of change - [x] Bug fix (non-breaking change that fixes an issue) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Think of the project like a package store with a safety rule: "Don't sell anything that just arrived today—wait a day to make sure it's safe." The problem was this rule was also stopping the store from using its own fresh products. The fix tells the store: "Apply this safety rule to packages from other suppliers, but trust our own products and use them right away." ## Overview This PR resolves a CI issue where pnpm's `minimumReleaseAge: 1440` setting (which enforces a 1-day maturity gate for package installation) was incorrectly blocking the installation of the project's own snapshot and canary builds during E2E tests. The fix adds a `minimumReleaseAgeExclude` configuration to `pnpm-workspace.yaml` that exempts first-party packages from this gate, while preserving the supply-chain security protection for third-party dependencies. ## Changes **pnpm-workspace.yaml**: Added `minimumReleaseAgeExclude` configuration with the following excluded package patterns: - `@mastra/*` (scoped packages) - `@internal/*` (internal scoped packages) - `mastra` (main package) - `create-mastra` (create-mastra package) This allows snapshot and canary builds to be installed immediately after publishing, unblocking E2E test flows (create-mastra, no-bundling, monorepo, deployers) that were previously failing with `ERR_PNPM_NO_MATURE_MATCHING_VERSION`. ## Impact - **Bug Fix**: Resolves CI failures for snapshot/canary E2E flows that publish and immediately install temporary 0.0.0-…-snapshot versions - **Security Preserved**: Third-party dependencies remain subject to the 1-day maturity requirement - **Non-breaking**: This is a configuration-only change with no impact on public APIs or breaking changes [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16495) <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
## Summary Adds Studio/playground support for Agent signal follow-up chat. Threaded chat sends now go through the signal-aware `useChat` path, while Studio keeps a passive subscription open for the active thread so other tabs can observe in-flight streams. Follow-up messages show a pending snippet until their signal echo arrives, then assistant chunks continue below the echoed user message. This also keeps the composer usable during active signal streams and wires stop/cancel through subscription abort handling. ## Stack Previous PR: mastra-ai#16231 — Use Agent signals for MastraCode follow-up chat This is PR 4 of the Agent signals stack: 1. mastra-ai#16229 — Core Agent signal runtime, server routes, and client-js API 2. mastra-ai#16438 — Route system reminders through Agent signals 3. mastra-ai#16231 — Use Agent signals for MastraCode follow-up chat 4. mastra-ai#16338 — Use Agent signals for Studio/playground follow-up chat ## What changed - Routes Studio threaded chat sends through Agent signals. - Keeps a passive thread subscription open so additional tabs can observe active streams. - Tracks pending follow-up snippets until their matching `data-user-message` signal echo arrives. - Ensures assistant chunks after an echoed signal user message render below that user message. - Keeps the composer active during signal streams by intercepting follow-up sends before assistant-ui blocks them. - Finishes streaming UI state when cancel/abort happens. - Preserves autoscroll follow behavior for rapid output while still allowing intentional user scroll-up. ## Test plan - `pnpm --filter ./client-sdks/react test src/lib/ai-sdk/utils/toUIMessage.test.ts -- --bail 1 --reporter=dot` - `pnpm --filter ./packages/playground-ui test -- --bail 1 --reporter=dot` - `pnpm --filter ./client-sdks/client-js test src/utils/process-mastra-stream.test.ts -- --bail 1 --reporter=dot` - `pnpm --filter ./packages/server test src/server/handlers/agents.test.ts -- --bail 1 --reporter=dot` - `pnpm build:server` - `pnpm build:playground-ui` - `pnpm --filter ./packages/playground build` - `pnpm build:cli` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Explanation This PR lets you send follow-up chat messages while an AI agent is still responding, without breaking things. Your new message shows up as pending until confirmed, other browser tabs can watch the response stream live, and a bug that used to duplicate messages is now fixed. --- ## Overview This PR adds Studio/playground support for Agent signal follow-up chat, enabling users to send threaded messages while streaming is active. Threaded chat sends are routed through a signal-aware path while Studio passively subscribes to threads for multi-tab observation. Follow-up messages render as pending until echoed by a data-user-message signal, after which assistant chunks continue below. The composer remains usable during active streams, and stop/cancel flows are wired through subscription abort handling. A companion fix prevents chat message duplication when sending during streaming. ## Changes ### Chat Hook Updates - `useChat` hook now supports thread-based user-message signal streaming when `threadId` is provided - Added thread subscription management with abort/key/promise refs - Implements fallback to legacy `streamUntilIdle` route when thread signals are unsupported - New callbacks: `onSignalSent`, `onSignalEcho`, `onThreadSignalsUnsupported` - Message deduplication by signal ID prevents duplicates when sending during streaming - Tool approval/decline output suppressed while thread subscription is active - Cancellation aborts active stream, closes thread subscription, and finalizes assistant messages ### Message Processing Utilities - Added `markStreamingPartsDone` and `finishStreamingAssistantMessage` helpers to normalize streaming state - Added `appendAssistantMessage` utility for consistent assistant message building - New `signalContentsToUserMessages` converts payload contents into UI user messages - Enhanced `toUIMessage` to handle `data-user-message` chunks with deduplication by signal/message ID - `data-user-message` handler converts chunk contents into multiple user messages and finalizes preceding assistant streaming parts - `start` chunk handler deduplicates using `payload.messageId` when present - `text-start` handler prevents duplicate streaming text parts via `textId` checking - `text-delta` handler creates new assistant message when none exists - Comprehensive test coverage for signal echoing, deduplication, mixed attachments, and abort behavior ### Playground UI Components - New `ThreadRuntimeState` context tracks streaming/cancel behavior and pending signals - Thread composer now uses `useThreadRuntimeState` for streaming-aware behavior - Composer input disables submit while streaming (when not permitted), enables Enter key during streaming only when allowed - Composer renders animated "pending:" preview list above input when pending messages exist - Send/cancel button refactored: renders cancel button during streaming, otherwise send button; cancel button works even when sending is disallowed ### Runtime State Management - `MastraRuntimeProvider` maintains thread-signal UI state with `pendingSignals` and `threadSignalsUnsupported` flag - Callbacks track pending signals on signal send/echo events - Refactored cancel path to abort via abort controller, clear refs, reset streaming state, and refresh UI - Provider wraps `AssistantRuntimeProvider` with `ThreadRuntimeStateProvider`, exposing streaming state and pending signals to consumers ### Documentation - Added Studio behavior clarification: follow-up messages during streaming appear as pending until confirmed, with multi-tab observation support ### Testing - Expanded `toUIMessage` test coverage for signal echoing, deduplication, and state transitions - Updated thread subscription cancellation test to verify abort/unsubscribe behavior - Bug fix: streaming chat messages no longer duplicate when sending during agent response, and previous response no longer marked as streaming ### Type Exports - `MastraChatProps`: added `threadId`, `onSignalSent`, `onSignalEcho`, `onThreadSignalsUnsupported` - `StreamArgs`: added optional `signalId` - `PendingSignalMessage` type for tracking pending signals - `ThreadRuntimeState` type for thread runtime context ## Impact - Users can send follow-up messages while agent is streaming without UI degradation - Multi-tab support allows observing in-flight streams across browser tabs - Fixes message duplication and streaming state bugs from prior streaming implementation - Backwards compatible: falls back to legacy streaming when servers lack signal-route support [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16338) <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
…a + deploy commands (mastra-ai#15728) ## What this ships End-to-end Mastra Observability onboarding from the CLI. After this PR, a user who scaffolds a new Mastra project and says "yes" to Observability is fully wired up to the hosted platform with no manual steps. ## Changes **`create-mastra` / `mastra init`** - New "Enable Mastra Observability? (will open auth flow)" prompt, plus `--observability` / `--no-observability` flags for non-interactive use and `--observability-project <name>` to bypass the picker. - When the user opts in, the CLI: 1. Runs the browser login flow inline if the user isn't authenticated. 2. Resolves the current organization (force-prompts the picker when the user belongs to multiple orgs, and persists the selection to `~/.mastra/credentials.json`). 3. For `mastra init`: lists existing projects and lets the user pick one or create a new one. For `create-mastra`: always creates a new project using the local project name (no picker, no re-prompt). 4. Creates projects as observability-only on the platform (`studioEnabled: false`, `serverEnabled: false`) so they aren't mislabelled as Studio in the UI. 5. Mints an org-scoped access token (`POST /v1/auth/tokens`) named `mastra observability – <projectName>`. 6. Writes `MASTRA_PLATFORM_ACCESS_TOKEN` + `MASTRA_PROJECT_ID` (and `MASTRA_CLOUD_TRACES_ENDPOINT` when targeting a non-prod platform) to `.env`. - The generated project registers `MastraPlatformExporter` out of the box. - Falls back to a placeholder `.env` block with manual instructions if provisioning fails, so init never hard-fails on network/auth issues. **`mastra studio deploy` / `mastra server deploy`** - Both commands now read `MASTRA_PROJECT_ID` and `MASTRA_ORG_ID` from the project's `.env` / `.env.local` / `.env.production` before resolving the target project, so projects scaffolded with Observability auto-link to the existing platform project instead of creating a duplicate on first deploy. Existing `process.env` values take precedence. - On first deploy to an observability-only project, the platform flips the matching runtime flag (`studioEnabled` / `serverEnabled`) so the project shows up correctly in the UI. **Refactor** - Lifts `resolveCurrentOrg` from `commands/studio/projects.ts` to `commands/auth/orgs.ts`, adds a `forcePrompt` option, and persists the picked org to `~/.mastra/credentials.json`. ## Test plan - `pnpm --filter ./packages/cli test` — green (includes new tests for `provisionObservabilityProject`, `writeObservabilityEnv`, `resolveCurrentOrg`, and `loadDeployEnvFromDotenv`). - `pnpm --filter ./packages/cli typecheck` — clean. - Verified end-to-end against the production platform: `create-mastra` provisions an observability-only project, mints a token, writes `.env`, and the resulting `MASTRA_PLATFORM_ACCESS_TOKEN` / `MASTRA_PROJECT_ID` pair successfully ingests spans. --------- Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `main` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `main`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## @mastra/client-js@1.18.0-alpha.15 ### Minor Changes - Added client, React, and Studio support for Agent signals in threaded chat. Threaded user messages now send through Agent signals, stream output is consumed from the thread subscription, echoed user messages are deduped by signal ID, file and image message contents are preserved, Studio can send follow-ups while a response is streaming, Studio subscribes to open threads so additional tabs can observe active streams, and the Studio stop button aborts the active thread subscription. React chat also falls back to legacy threaded streaming when it connects to a server or core version that does not support signal routes yet. ([mastra-ai#16338](mastra-ai#16338)) ```ts const { sendMessage } = useChat({ agentId, resourceId, threadId }); await sendMessage({ message: 'Follow up while streaming', threadId }); ``` ### Patch Changes - Updated dependencies: - @mastra/core@1.33.0-alpha.14 ## @mastra/react@0.3.0-alpha.15 ### Minor Changes - Added client, React, and Studio support for Agent signals in threaded chat. Threaded user messages now send through Agent signals, stream output is consumed from the thread subscription, echoed user messages are deduped by signal ID, file and image message contents are preserved, Studio can send follow-ups while a response is streaming, Studio subscribes to open threads so additional tabs can observe active streams, and the Studio stop button aborts the active thread subscription. React chat also falls back to legacy threaded streaming when it connects to a server or core version that does not support signal routes yet. ([mastra-ai#16338](mastra-ai#16338)) ```ts const { sendMessage } = useChat({ agentId, resourceId, threadId }); await sendMessage({ message: 'Follow up while streaming', threadId }); ``` ### Patch Changes - Fixed streaming chat messages so sending while an agent is running does not duplicate assistant output or leave the previous response marked as streaming. ([mastra-ai#16338](mastra-ai#16338)) - Updated dependencies \[[`05dab92`](mastra-ai@05dab92)]: - @mastra/client-js@1.18.0-alpha.15 - @mastra/core@1.33.0-alpha.14 ## mastra@1.9.0-alpha.15 ### Minor Changes - Add "Enable Mastra Observability? (will open auth flow)" prompt to `create-mastra` and `mastra init`. ([mastra-ai#15728](mastra-ai#15728)) When the user opts in, the CLI runs the interactive browser login flow (if not already authenticated), lets them pick an existing project or create a new one, mints a fresh organization access token, and writes `MASTRA_PLATFORM_ACCESS_TOKEN` + `MASTRA_PROJECT_ID` to `.env`. The generated project already registers a `MastraPlatformExporter`, so no additional setup is needed to start sending traces. `MASTRA_PLATFORM_ACCESS_TOKEN` replaces `MASTRA_CLOUD_ACCESS_TOKEN`. The old name is still read by the exporter for backwards compatibility but is deprecated. If provisioning fails (e.g., the platform is unreachable), the command falls back to writing placeholder env vars with instructions. Both commands also accept `--observability` / `--no-observability` flags for non-interactive use, and `--observability-project <name>` to bypass the project picker. ### Patch Changes - `mastra studio deploy` and `mastra server deploy` now read `MASTRA_PROJECT_ID` and `MASTRA_ORG_ID` from the project's `.env` file, so projects scaffolded with Mastra Observability auto-link to the existing platform project on first deploy instead of creating a new one. Existing `process.env` values still take precedence. ([mastra-ai#15728](mastra-ai#15728)) - Mastra Observability provisioning now creates new platform projects as observability-only (no Studio or Server runtime attached). The first `mastra studio deploy` or `mastra server deploy` flips the matching runtime flag, so projects are no longer mislabelled as Studio in the platform UI before any deploy has happened. ([mastra-ai#15728](mastra-ai#15728)) - `mastra studio deploy` and `mastra server deploy` now prompt you to pick from existing projects in the selected organization instead of silently matching by `package.json` name or always creating a new project. ([mastra-ai#15728](mastra-ai#15728)) **What changed** - When existing projects are found, both commands show an interactive selector listing them (plus a "Create new project" option). - `--project <id-or-slug>` still bypasses the selector for non-interactive use. - `-y/--yes` auto-accepts only when there is exactly one project whose name or slug matches the local `package.json` name; otherwise it errors asking you to pass `--project`. - Projects saved in `.mastra-project.json` for the same organization are still auto-matched (no prompt). This fixes deploys accidentally creating duplicate projects or targeting the wrong existing project when the local package name happened to collide. - Updated dependencies: - @mastra/deployer@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## create-mastra@1.9.0-alpha.15 ### Minor Changes - Add "Enable Mastra Observability? (will open auth flow)" prompt to `create-mastra` and `mastra init`. ([mastra-ai#15728](mastra-ai#15728)) When the user opts in, the CLI runs the interactive browser login flow (if not already authenticated), lets them pick an existing project or create a new one, mints a fresh organization access token, and writes `MASTRA_PLATFORM_ACCESS_TOKEN` + `MASTRA_PROJECT_ID` to `.env`. The generated project already registers a `MastraPlatformExporter`, so no additional setup is needed to start sending traces. `MASTRA_PLATFORM_ACCESS_TOKEN` replaces `MASTRA_CLOUD_ACCESS_TOKEN`. The old name is still read by the exporter for backwards compatibility but is deprecated. If provisioning fails (e.g., the platform is unreachable), the command falls back to writing placeholder env vars with instructions. Both commands also accept `--observability` / `--no-observability` flags for non-interactive use, and `--observability-project <name>` to bypass the project picker. ### Patch Changes - Mastra Observability provisioning now creates new platform projects as observability-only (no Studio or Server runtime attached). The first `mastra studio deploy` or `mastra server deploy` flips the matching runtime flag, so projects are no longer mislabelled as Studio in the platform UI before any deploy has happened. ([mastra-ai#15728](mastra-ai#15728)) ## @mastra/server@1.33.0-alpha.14 ### Minor Changes - Added client, React, and Studio support for Agent signals in threaded chat. Threaded user messages now send through Agent signals, stream output is consumed from the thread subscription, echoed user messages are deduped by signal ID, file and image message contents are preserved, Studio can send follow-ups while a response is streaming, Studio subscribes to open threads so additional tabs can observe active streams, and the Studio stop button aborts the active thread subscription. React chat also falls back to legacy threaded streaming when it connects to a server or core version that does not support signal routes yet. ([mastra-ai#16338](mastra-ai#16338)) ```ts const { sendMessage } = useChat({ agentId, resourceId, threadId }); await sendMessage({ message: 'Follow up while streaming', threadId }); ``` ### Patch Changes - Updated dependencies: - @mastra/core@1.33.0-alpha.14 ## @mastra/deployer-cloud@1.33.0-alpha.14 ### Patch Changes - Updated dependencies: - @mastra/deployer@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/longmemeval@1.0.38-alpha.15 ### Patch Changes - Updated dependencies: - @mastra/core@1.33.0-alpha.14 ## @mastra/opencode@0.0.35-alpha.15 ### Patch Changes - Updated dependencies: - @mastra/core@1.33.0-alpha.14 ## mastracode@0.18.0-alpha.16 ### Patch Changes - Updated dependencies: - @mastra/core@1.33.0-alpha.14 ## @mastra/deployer@1.33.0-alpha.14 ### Patch Changes - Updated dependencies \[[`05dab92`](mastra-ai@05dab92)]: - @mastra/server@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/mcp-docs-server@1.1.35-alpha.27 ### Patch Changes - Updated dependencies: - @mastra/core@1.33.0-alpha.14 ## @mastra/playground-ui@27.0.0-alpha.15 ### Patch Changes - Changed the default Observability list mode to branches (all traces, including nested). The query logic still recognizes `?listMode=traces` to opt back into the top-level-only view. ([mastra-ai#16493](mastra-ai#16493)) **Before** `/observability` → top-level traces only **After** `/observability` → branches (all traces, nested too) `/observability?listMode=traces` → top-level traces only - Updated dependencies \[[`05dab92`](mastra-ai@05dab92), [`05dab92`](mastra-ai@05dab92)]: - @mastra/react@0.3.0-alpha.15 - @mastra/client-js@1.18.0-alpha.15 - @mastra/core@1.33.0-alpha.14 ## @mastra/express@1.3.19-alpha.14 ### Patch Changes - Updated dependencies \[[`05dab92`](mastra-ai@05dab92)]: - @mastra/server@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/fastify@1.3.19-alpha.14 ### Patch Changes - Updated dependencies \[[`05dab92`](mastra-ai@05dab92)]: - @mastra/server@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/hono@1.4.14-alpha.14 ### Patch Changes - Updated dependencies \[[`05dab92`](mastra-ai@05dab92)]: - @mastra/server@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/koa@1.5.2-alpha.14 ### Patch Changes - Updated dependencies \[[`05dab92`](mastra-ai@05dab92)]: - @mastra/server@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/nestjs@0.1.3-alpha.14 ### Patch Changes - Updated dependencies \[[`05dab92`](mastra-ai@05dab92)]: - @mastra/server@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/temporal@0.1.2-alpha.14 ### Patch Changes - Updated dependencies: - @mastra/deployer@1.33.0-alpha.14 - @mastra/core@1.33.0-alpha.14 ## @mastra/core@1.33.0-alpha.14 ## @internal/playground@1.9.0-alpha.15 ### Patch Changes - Updated dependencies \[[`05dab92`](mastra-ai@05dab92), [`05dab92`](mastra-ai@05dab92), [`99a579b`](mastra-ai@99a579b)]: - @mastra/react@0.3.0-alpha.15 - @mastra/client-js@1.18.0-alpha.15 - @mastra/playground-ui@27.0.0-alpha.15 - @mastra/core@1.33.0-alpha.14 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Description <!-- Required: Provide a brief description of the changes in this PR. --> ## Related issue(s) <!-- Required: Link to the issue(s) this PR addresses, e.g. with: Fixes mastra-ai#123. PRs without linked issues may be closed. --> ## Type of change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [ ] I have linked the related issue(s) in the description above - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR stabilizes end-to-end tests by switching them to an internal LLM test-mode that injects per-test dummy API keys, bumps timeouts for a few slow Gemini tests, and updates CI to pull real credentials from GitHub Secrets so tests can authenticate to external services. ## Changes ### Test setup: use internal LLM test-mode + dummy API keys - Many e2e test files were updated to use internal test utilities (getLLMTestMode + setupDummyApiKeys) instead of dotenv. Each now calls setupDummyApiKeys(getLLMTestMode(), [...providers]) at module/test init to provision provider-specific dummy keys. Examples of affected tests include: - packages/core/src/agent/agent-gemini.e2e.test.ts - packages/core/src/agent/__tests__/* (image-prompt, prefill-error-recovery, reasoning-openai-summaries, save-and-errors, stopWhen, tool-approval, tool-calls-finish-reason, tool-handling, workspace-tools-openai) - packages/core/src/agent/* (agent-network, agent-processor) - packages/core/src/agent/durable/__tests__/durable-agent-background-tasks.e2e.test.ts - packages/core/src/background-tasks/background-tasks.e2e.test.ts - packages/core/src/llm/model/model.loop.e2e.test.ts - packages/core/src/processors/* (structured-output, token-accuracy) - packages/core/src/processors/provider-history-compat.e2e.test.ts - packages/core/src/tools/* (provider-tools-ordering, provider-tools-persistence, tool-builder/builder.e2e.test.ts) - packages/core/src/voice/aisdk/__tests__/* (aisdk-voice, composite-voice) - packages/evals/src/scorers/llm/* (answer-similarity, context-precision, context-relevance, faithfulness, hallucination, noise-sensitivity, prompt-alignment, tool-call-accuracy, toxicity) - The dotenv/config() usage was removed where present. Test logic and assertions were preserved; no public API surface changes. ### Timeout adjustment for Gemini tests - packages/core/src/agent/agent-gemini.e2e.test.ts: - Adds setupDummyApiKeys(getLLMTestMode(), ['google']). - Increases per-test timeouts for three Gemini-related e2e tests from 40,000ms to 120,000ms. - No assertions changed. ### CI workflow: replace placeholders with GitHub Secrets - .github/workflows/test-suite.yml: - e2e-test job now sources environment variables from GitHub Secrets instead of hardcoded placeholders. - Secrets added/used include LLM keys and service credentials such as OPENAI_API_KEY, OPENROUTER_API_KEY, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, COHERE_API_KEY, PINECONE_API_KEY, ASTRA_DB_ENDPOINT/TOKEN, CLOUDFLARE_API_TOKEN/ACCOUNT_ID, KV_REST_API_URL/KV_REST_API_TOKEN, etc., enabling CI to provide real credentials for external integrations. ## Other notes - Changes are test-only and CI configuration; no exported/public API declarations were modified. - PR description lacks implementation details and linked issues; the single commit message ("fix") is generic and checklist items in the PR body are unchecked. [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16486) <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This adds an experimental `A2AAgent` to `@mastra/core/a2a` so a Mastra
agent can use a remote A2A agent as a subagent.
The main story here is registering a remote agent card URL on a parent
agent and letting Mastra delegate to it through the normal subagent
path.
```ts
import { Agent } from '@mastra/core/agent';
import { A2AAgent } from '@mastra/core/a2a';
const supportAgent = new Agent({
name: 'Support Agent',
model,
agents: {
remoteWeather: new A2AAgent({
url: 'https://example.com/.well-known/agent-card.json',
}),
},
});
```
`A2AAgent` handles agent card discovery/bootstrap, remote `generate` /
`resumeGenerate`, remote `stream` / `resumeStream`, suspend-resume
payloads, optional agent card verification, and the browser-safe shared
A2A imports used by `client-js` via `@mastra/core/a2a/client`.
I also tightened the stream path a bit while building this out:
malformed SSE frames are skipped instead of aborting the run,
non-transient 4xx responses are not retried, and the focused tests now
cover the subagent path plus those stream edge cases.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This PR lets one AI agent use another AI agent as a helper. Instead of
doing all the work itself, an agent can send tasks to a remote AI agent
and get back the results—kind of like asking a friend for help instead
of doing something alone.
---
## Changes Summary
This PR introduces an experimental **A2AAgent** implementation that
enables Mastra agents to delegate work to remote A2A agents via a
subagent pattern. The implementation includes comprehensive testing,
stream robustness improvements, and a browser-safe client surface for
shared types.
### Core Implementation
- **A2AAgent** class added at `@mastra/core/a2a` implementing the
`SubAgent` interface
- Supports `generate()`, `resumeGenerate()`, `stream()`, and
`resumeStream()` methods for remote A2A execution over JSON-RPC
- Auto-discovers and caches remote Agent Cards in memory
- Supports optional agent card verification before execution
- Handles request retries with exponential backoff, timeouts, and
credentials
- Implements suspend–resume payload handling for multi-turn interactions
### Stream Handling & Robustness
- Malformed SSE frames are now skipped instead of aborting stream
processing
- Non-transient HTTP 4xx responses are no longer retried
- Stream consumption supports both SSE-based and buffered fallback modes
- Proper cleanup of stream locks and cancellation tokens
### Browser-Safe Client Surface
- New public export subpath `@mastra/core/a2a/client` provides
browser-compatible types and error classes
- Client-JS can now reuse A2A protocol types and errors without
Node-only runtime dependencies
- Reorganized type exports to separate client-safe interfaces from
internal implementation
### Testing & Validation
- 823-line comprehensive test suite for A2AAgent covering:
- Agent card caching and verification behavior
- Non-streaming and streaming execution paths
- Resume/continuation scenarios
- SSE stream edge cases and error handling
- Subagent integration with parent agent memory
- 6-line regression test ensuring AgentBadge renders correctly for
subagent content
### Build & Configuration
- Updated `package.json` exports map with new `./a2a/client` subpath
(ESM and CJS targets with shared type definitions)
- Added `src/a2a/client.ts` to tsup build configuration
- Reorganized module exports: moved bulk type/error re-exports from main
index to client barrel
### Type System Additions
New public types in `@mastra/core/a2a/types`:
- `A2AAgentOptions` – configuration for agent card URL, verification,
fetch, timeout, retry, and credential handling
- `A2AAgentVerificationOptions` & `A2AAgentCardVerificationContext` –
optional card verification hooks
- `A2AAgentRunState` – tracks run/task/context identifiers and card URLs
- `A2AAgentResumePayload` – suspend–resume state for multi-turn
execution
- `A2AAgentGenerateResult` & `A2AAgentStreamResult` – typed results for
generation and streaming
### Client-JS Updates
- Updated imports across test files, resources, and utilities to use
`@mastra/core/a2a/client` instead of `@mastra/core/a2a`
- Improved agent card signature tampering in tests to use base64url
byte-flipping instead of character substitution
### UI Refinement
- `AgentBadge` no longer defaults badge to collapsed state; now
consistently renders open for both live and hydrated subagent content
[](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16348)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com>
## Summary
- start the platform login/token flow immediately after users opt in to
observability during create/init prompts
- reuse that authenticated state later when provisioning the
observability project
- add prompt-level coverage to ensure auth only starts for the yes path
## Test plan
- pnpm --filter mastra exec vitest run src/commands/init/utils.test.ts
src/commands/init/observability-provision.test.ts
- pnpm --filter mastra typecheck
- pnpm --filter mastra build:lib
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5 (Explain Like I'm 5)
When you answer "yes" to "Do you want monitoring?", the CLI now
immediately logs you into the platform so it's ready to set up
monitoring right away, instead of asking for credentials later.
---
## Changes Overview
### packages/cli/src/commands/init/utils.ts
- Added export: `promptForObservability()` — prompts the user and, if
they opt in, immediately runs the platform auth flow via `getToken()`
and returns `{ enabled: true, token }`.
- Added `ObservabilityPromptResult` type: `{ enabled?: boolean; token?:
string }`.
- Refactored `interactivePrompt` to delegate the observability step to
`promptForObservability()` and to include `observability` and
`observabilityToken` when flattening results.
### packages/cli/src/commands/init/utils.test.ts
- Added tests for `promptForObservability()` with mocks for
`@clack/prompts` and `../auth/credentials.js`.
- Test cases:
- When select returns "yes": resolves to `{ enabled: true, token:
'platform-token' }` and calls `getToken`.
- When select returns "no": resolves to `{ enabled: false }` and does
not call `getToken`.
- Consolidated async imports/setup for observability-related tests.
### packages/cli/src/commands/init/observability-provision.ts
- Updated `provisionObservabilityProject` signature to accept an
optional `token` parameter.
- If `token` is provided, uses it instead of calling `getToken()`;
otherwise falls back to `await getToken()`.
### packages/cli/src/commands/init/observability-provision.test.ts
- Added a test verifying that when a token is passed into provisioning,
`getToken` is not called and the provision flow uses the provided token
(calls `resolveCurrentOrg` with the token and `{ forcePrompt: true }`).
### packages/cli/src/commands/actions/init-project.ts and
packages/cli/src/commands/create/create.ts
- Thread `observabilityToken` from the interactive prompt result into
`init(...)` so the token obtained at prompt time is reused during
provisioning.
### packages/cli/src/commands/init/init.ts
- `init` now accepts an optional `observabilityToken` option and
forwards it to `provisionObservabilityProject({ token:
observabilityToken })`.
### .changeset/cli-observability-auth-prompt.md
- New changeset documenting the behavior: start platform auth
immediately when users opt into observability during create/init and
reuse the token for provisioning.
---
## Impact
- User experience: authentication is paired with the observability
opt-in prompt, eliminating a later credential prompt and enabling a
smoother provisioning flow.
- Behavior: the token obtained at opt-in is reused for observability
project provisioning; code paths that previously always called
`getToken()` now accept and prefer a supplied token.
[](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16502)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
) ## Summary - Allow MastraPlatformExporter to use MASTRA_PLATFORM_ACCESS_TOKEN when present, falling back to MASTRA_CLOUD_ACCESS_TOKEN - Keep explicit accessToken config precedence over environment variables - Update observability tests and the missing-token debug expectation ## Test plan - pnpm --filter @mastra/observability exec vitest run src/exporters/mastra-platform.test.ts src/registry.test.ts - pnpm --filter @mastra/observability build <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR makes the observability exporter look for a second environment variable (MASTRA_PLATFORM_ACCESS_TOKEN) to authenticate with the cloud and prefer it over the older MASTRA_CLOUD_ACCESS_TOKEN when no explicit token is configured. ## Changes ### Core Changes **observability/mastra/src/exporters/mastra-platform.ts** - Resolve `accessToken` from, in order: `config.accessToken`, `MASTRA_PLATFORM_ACCESS_TOKEN`, then `MASTRA_CLOUD_ACCESS_TOKEN`. - Update the debug message shown when no token is available to mention both `MASTRA_PLATFORM_ACCESS_TOKEN` and `MASTRA_CLOUD_ACCESS_TOKEN`. ### Test Updates **observability/mastra/src/exporters/mastra-platform.test.ts** - Added four integration tests verifying Authorization header selection when no explicit token is configured: - Uses `MASTRA_CLOUD_ACCESS_TOKEN` when only the cloud token is set. - Uses `MASTRA_PLATFORM_ACCESS_TOKEN` when only the platform token is set. - Prefers `MASTRA_PLATFORM_ACCESS_TOKEN` when both env vars are present. - Falls back to `MASTRA_CLOUD_ACCESS_TOKEN` when `MASTRA_PLATFORM_ACCESS_TOKEN` is set to an empty string. - Each test stubs environment variables with `vi.stubEnv`, exports a span, flushes to trigger the HTTP call, asserts the mocked request's `Authorization` header, and restores state in a `finally` block. **observability/mastra/src/registry.test.ts** - The missing-token test now stubs both `MASTRA_CLOUD_ACCESS_TOKEN` and `MASTRA_PLATFORM_ACCESS_TOKEN` (the latter as empty) and updates the expected DEBUG message to reference both environment variable names. ### Changeset **.changeset/platform-observability-token-env.md** - Added a patch changeset documenting support for `MASTRA_PLATFORM_ACCESS_TOKEN` while retaining `MASTRA_CLOUD_ACCESS_TOKEN` as a fallback. ## Notes - No public API changes. - Test plan: - pnpm --filter @mastra/observability exec vitest run src/exporters/mastra-platform.test.ts src/registry.test.ts - pnpm --filter @mastra/observability build [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16500) <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `main` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `main`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## @mastra/core@1.33.0-alpha.15 ### Minor Changes - Added experimental support for using remote A2A agents as Mastra subagents. ([mastra-ai#16348](mastra-ai#16348)) **What changed** - Mastra agents can register remote A2A endpoints through `A2AAgent` and delegate to them like other subagents. - Remote A2A subagents support `generate`, `resumeGenerate`, `stream`, and `resumeStream` so parent agents can use them in normal subagent flows. - Agent Cards can be cached and verified with pluggable verification hooks before remote execution begins. - Browser environments can import shared A2A types and errors from `@mastra/core/a2a/client`. **Example** ```ts import { Agent } from '@mastra/core/agent'; import { A2AAgent } from '@mastra/core/a2a'; const agent = new Agent({ name: 'Support Agent', instructions: 'Use the remote billing specialist for billing questions.', model: 'openai/gpt-4o-mini', agents: { billingSpecialist: new A2AAgent({ url: 'https://billing.example.com/.well-known/agent-card.json', }), }, }); const result = await agent.generate('Can you check the latest invoice status?'); ``` **Why** This lets Mastra agents compose with remote A2A agents without exposing those integrations as plain tools or depending directly on the client SDK. ## @mastra/client-js@1.18.0-alpha.16 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 ## @mastra/react@0.3.0-alpha.16 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/client-js@1.18.0-alpha.16 ## @mastra/deployer-cloud@1.33.0-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/deployer@1.33.0-alpha.15 ## @mastra/longmemeval@1.0.38-alpha.16 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 ## @mastra/opencode@0.0.35-alpha.16 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 ## mastracode@0.18.0-alpha.17 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 ## @mastra/arize@1.1.0-alpha.5 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/otel-exporter@1.1.0-alpha.5 ## @mastra/arthur@0.2.10-alpha.5 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/otel-exporter@1.1.0-alpha.5 ## @mastra/braintrust@1.1.0-alpha.4 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 ## @mastra/datadog@1.2.0-alpha.5 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 ## @mastra/laminar@1.1.0-alpha.4 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 ## @mastra/langfuse@1.3.0-alpha.5 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 - @mastra/otel-exporter@1.1.0-alpha.5 ## @mastra/langsmith@1.2.0-alpha.4 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 ## @mastra/observability@1.12.0-alpha.4 ### Patch Changes - Support `MASTRA_PLATFORM_ACCESS_TOKEN` as the preferred environment variable for `MastraPlatformExporter`, while retaining `MASTRA_CLOUD_ACCESS_TOKEN` as a fallback for backward compatibility. ([mastra-ai#16500](mastra-ai#16500)) - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 ## @mastra/otel-bridge@1.1.0-alpha.5 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 - @mastra/otel-exporter@1.1.0-alpha.5 ## @mastra/otel-exporter@1.1.0-alpha.5 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 ## @mastra/posthog@1.0.24-alpha.4 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 ## @mastra/sentry@1.0.23-alpha.5 ### Patch Changes - Updated dependencies \[[`8781d45`](mastra-ai@8781d45), [`105e454`](mastra-ai@105e454)]: - @mastra/observability@1.12.0-alpha.4 - @mastra/core@1.33.0-alpha.15 - @mastra/otel-exporter@1.1.0-alpha.5 ## mastra@1.9.0-alpha.16 ### Patch Changes - Start the Mastra Platform auth flow immediately after users opt in to observability during `create mastra` and `mastra init`, then reuse that token when provisioning the observability project. ([mastra-ai#16502](mastra-ai#16502)) - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/deployer@1.33.0-alpha.15 ## @mastra/deployer@1.33.0-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/server@1.33.0-alpha.15 ## @mastra/mcp-docs-server@1.1.35-alpha.28 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 ## @mastra/playground-ui@27.0.0-alpha.16 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/client-js@1.18.0-alpha.16 - @mastra/react@0.3.0-alpha.16 ## @mastra/server@1.33.0-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 ## @mastra/express@1.3.19-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/server@1.33.0-alpha.15 ## @mastra/fastify@1.3.19-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/server@1.33.0-alpha.15 ## @mastra/hono@1.4.14-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/server@1.33.0-alpha.15 ## @mastra/koa@1.5.2-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/server@1.33.0-alpha.15 ## @mastra/nestjs@0.1.3-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/server@1.33.0-alpha.15 ## @mastra/temporal@0.1.2-alpha.15 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/deployer@1.33.0-alpha.15 ## create-mastra@1.9.0-alpha.16 ## @internal/playground@1.9.0-alpha.16 ### Patch Changes - Updated dependencies \[[`105e454`](mastra-ai@105e454)]: - @mastra/core@1.33.0-alpha.15 - @mastra/client-js@1.18.0-alpha.16 - @mastra/react@0.3.0-alpha.16 - @mastra/playground-ui@27.0.0-alpha.16 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…2E jobs (mastra-ai#16505) ## Problem mastra-ai#16462 added `minimumReleaseAge: 1440` to `pnpm-workspace.yaml` ahead of pnpm v11 default, as a supply-chain defense against newly-published malicious third-party packages. mastra-ai#16495 added `minimumReleaseAgeExclude` to exempt our own packages (`@mastra/*`, `@internal/*`, `mastra`, `create-mastra`) so the gate did not block our snapshot/canary E2E flows. That fixed the in-workspace case but the snapshot E2E jobs are still failing: ``` ERR_PNPM_NO_MATURE_MATCHING_VERSION Version 0.0.0-no-bundling-test-…-snapshot (released just now) of @mastra/loggers does not meet the minimumReleaseAge constraint ``` The reason: these jobs publish a snapshot to a **local registry**, then install it inside a **freshly generated project under `/tmp/…`**. That generated project is outside the workspace and has no `pnpm-workspace.yaml`, so the workspace-level `minimumReleaseAgeExclude` setting does not apply. Affected jobs: - `E2E monorepo` - `E2E no-bundling` - `E2E create-mastra` - `E2E deployers` ## Fix Set `NPM_CONFIG_MINIMUM_RELEASE_AGE_EXCLUDE='@mastra/* @internal/* mastra create-mastra'` on each affected job Test step. This mirrors the workspace-level `minimumReleaseAgeExclude` but applies inside the generated `/tmp/…` project where the workspace config does not reach. ## Why this is the right scope The `minimumReleaseAge` defense exists to prevent CI/dev installs from immediately picking up malicious third-party publishes before the ecosystem can detect them. The exclude env keeps that defense intact for third-party deps while letting our own freshly-built snapshots install: - Only our **own first-party packages** (`@mastra/*`, `@internal/*`, `mastra`, `create-mastra`) are exempted - **Third-party transitive deps** pulled in by the generated `/tmp/…` project still go through the 1-day gate — a newly published malicious npm package would still be blocked - The exclude env is scoped to the `Test` step of these four jobs; every other `pnpm install` in CI (workspace bootstrap, lint, etc.) is unaffected - The whole `/tmp/…` project is discarded at job end Compared to alternatives: - **`NPM_CONFIG_MINIMUM_RELEASE_AGE=0`** would also bypass the gate for every third-party package the generated project transitively installs, weakening supply-chain defense on the CI runner. - **Patching the `mastra build` output template** to ship `minimumReleaseAgeExclude` to every generated user project would leak CI-test concerns into production code. - **Dropping `minimumReleaseAge` entirely** would undo mastra-ai#16462 supply-chain defense for real workspace installs. ## Test plan - `E2E Tests` on this PR should no longer fail with `ERR_PNPM_NO_MATURE_MATCHING_VERSION` for our own snapshot versions. - Workspace bootstrap, `Build`, and `Install dependencies` steps still run with the gate in effect, so third-party packages newer than 24h are still blocked everywhere else, including inside the generated `/tmp/…` project. Co-Authored-By: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
…ra-ai#16799) Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
…fresh (mastra-ai#16788) ## Summary - Replace `@radix-ui/react-slider` with `@base-ui/react/slider` as the underlying primitive - Refreshed visuals: rounded thumb with neutral border + neutral inside, opacity-based track that adapts to any surface, neutral filled indicator (no accent / green color) - Bigger interactive area: padded `Slider.Control` for a tall click target + invisible `::after` halo on the thumb so it's easier to grab - `cursor-pointer` on the control, `cursor-not-allowed` when disabled - `onValueChange` / `onValueCommitted` wrapped to always emit `number[]`, preserving the existing consumer API even though base-ui returns `number | number[]` internally - Drop unused `@radix-ui/react-slider` and `@radix-ui/react-tabs` dependencies - Stories expanded with `ThreeThumbs`, `PriceRange`, `Vertical`, `States` showcase + a live-value `WithLabel` ## Where it's used - `packages/playground/src/domains/agents/components/agent-settings.tsx` (Temperature & Top P) - `packages/playground/src/domains/workflows/workflow/zoom-slider.tsx` (workflow zoom) Both consumers pass `value={[number]}` and use `value[0]` in `onValueChange` — no consumer changes required. ## Test plan - [ ] Storybook (`packages/playground-ui`, port 6006): verify Default, WithRange, ThreeThumbs, Disabled, Vertical, States stories - [ ] Drag, click-on-track, and keyboard (Arrow keys, PageUp/Down) all update the value - [ ] Local studio (`pnpm dev:playground`) → open an agent → Model Settings → Temperature & Top P sliders drag smoothly, value reflects in the label, snaps to `n/a` at min - [ ] Workflow graph zoom slider still controls zoom level - [ ] Track remains visible on `surface2` / `surface3` / `surface4` panels (opacity-based color) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 The slider you drag to change settings was rebuilt using a different, simpler building block so it looks more neutral, is easier to grab, and keeps working the same for the rest of the app. ## Overview Migrates the playground Slider from `@radix-ui/react-slider` to `@base-ui/react/slider`, applies a neutral visual refresh, increases hit targets/usability, preserves the public API shape, removes unused Radix deps, and expands Storybook coverage. ## Key Changes - Component migration - Replaced Radix Slider primitive with Base UI Slider primitive. - Converted from a React.forwardRef implementation to a plain functional component. - Added a SliderProps type that normalizes callback signatures. - API compatibility - Wrapped onValueChange and onValueCommitted to always emit number[] (preserves existing consumer expectations despite Base UI returning number | number[]). - Visual & interaction refresh - Rounded thumb with neutral border and neutral fill; neutral filled indicator (removed accent/green). - Track uses opacity so it adapts to surface backgrounds. - Increased interactive area: padded Slider.Control and invisible ::after halo on the thumb to improve grabability. - cursor-pointer on Control; cursor-not-allowed when disabled. - Focus/interaction classes updated for Base UI. - Stories & docs - Storybook stories expanded and updated: - Wider default width for many stories (w-[240px]). - WithLabel converted to a controlled example showing live value. - New stories: PriceRange, Vertical, States, ThreeThumbs, and live-value WithLabel. - Dependencies & housekeeping - Removed unused `@radix-ui/react-slider` and `@radix-ui/react-tabs`. - Changeset added and formatting/prettier fixes applied. ## Files / Types Changed - packages/playground-ui/src/ds/components/Slider/slider.tsx - New SliderProps type. - Implementation switched to Base UI primitives; value normalization logic added; multiple thumbs rendered from values array. - packages/playground-ui/src/ds/components/Slider/slider.stories.tsx - Story updates and additions as listed above. - packages/playground-ui/package.json - Removed Radix slider/tabs deps from dependencies. - .changeset/thirty-shrimps-brake.md - Changeset documenting the migration. ## Consumers & Impact - No breaking changes expected. Consumers already pass value={[number]} and read value[0] in: - packages/playground/src/domains/agents/components/agent-settings.tsx (Temperature & Top P) - packages/playground/src/domains/workflows/workflow/zoom-slider.tsx - Verify Storybook (port 6006) and interactions: drag, click-on-track, keyboard, and slider visibility on surface2/3/4 panels. ## Test Plan / Review Notes - Check Storybook stories: Default, WithRange, ThreeThumbs, Disabled, Vertical, States, WithLabel/PriceRange. - Validate drag, click-on-track, and keyboard input update values and callbacks receive number[]. - Confirm sliders in local studio agent settings and workflow zoom behave identically visually and functionally. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16788?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Add focused Vitest coverage for the agent builder hooks package
- Cover autosave, access gating, tool creation, visibility changes,
channel toasts, chat draft, save-agent, and model-policy filtering flows
- Add missing playground hook/domain modules needed by the agent builder
hook surface
## Test plan
- pnpm exec vitest run
src/domains/agent-builder/hooks/__tests__/builder-hooks.test.tsx
--coverage.enabled --coverage.provider=v8
--coverage.include='src/domains/agent-builder/hooks/**/*.{ts,tsx}'
## Notes
- Targeted hook coverage reports 100% statements, branches, functions,
and lines.
- packages/playground typecheck was checked earlier and currently fails
on existing unrelated playground TypeScript errors outside this hook
coverage work.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This PR adds many small pieces of code ("hooks") that make the
agent-builder UI work reliably — they auto-save edits, enforce who can
do what, let users create and attach skills/tools, manage visibility
changes, and filter which AI models are allowed. It also ships a
thorough test suite that verifies all those behaviors.
---
## Overview
Adds a comprehensive hook suite and supporting utilities for the agent
builder frontend, plus focused Vitest tests that exercise autosave,
access gating, tool creation/execution, visibility flows,
channel-toasts, chat drafts, save flows, and model-policy filtering.
Introduces domain helpers for model/provider filtering and small
auth/default helpers. Targeted test coverage for the hooks reports 100%
statements/branches/functions/lines.
---
## Test Coverage
- File:
packages/playground/src/domains/agent-builder/hooks/__tests__/builder-hooks.test.tsx
- Scope: Extensive Vitest + React Testing Library suite covering:
- Access control and create-route selection (useBuilderAgentAccess,
useCanCreateAgent)
- Form-backed tool execution and picker tooling (useAgentBuilderTool,
useAvailableAgentTools)
- Skill creation tooling and workspace handling (useCreateSkillTool)
- Save and autosave flows (useSaveAgent, useAutosaveAgent,
useAutosaveSkill)
- Visibility-change dialogs and flows for agents/skills
(useVisibilityChangeDialog + wrappers)
- Small interaction hooks (useAutoScroll, useChatDraft,
useChannelConnectToast, useStarterUserMessage)
- Channel-connect toast behavior and starter-user-message clearing
- Dialog/filtering behavior for tool/agent selection and allowlists
- Test infra: MSW/React Query/JSdom wiring, react-hook-form test
wrapper, deferred promise helpers
- Coverage: 100% statements, branches, functions, lines (for targeted
hook files)
---
## New/Changed Hooks & Exports (high level)
Access & permissions
- useBuilderAgentAccess() — RBAC-aware builder access flags, builder
feature gating, structured denial reasons
- useCanCreateAgent() — Determines create-route and eligibility
(experimental UI flag or builder access)
Form & tools
- useAgentBuilderTool() — Tool that applies input into the builder
react-hook-form (name, description, tools, skills/agents/workflows,
models, workspaceId, browserEnabled)
- useCreateSkillTool() — Tool to create a stored skill (workspace
validation, visibility defaulting, form updates)
- useConnectChannelTool(), CONNECT_CHANNEL_TOOL_NAME — Inline
connectChannel tool skeleton
Autosave & persistence
- useSaveAgent() — Builds save payloads, calls mutation, shows toasts,
classifies model-policy errors
- useAutosaveAgent() — Debounced autosave for agent forms with status,
stale-request handling, retry/flush
- useAutosaveSkill() — Debounced autosave for skill edits, regenerates
file tree, status and error handling
Visibility & interactions
- useVisibilityChangeDialog() — Generic confirmation dialog hook for
visibility changes
- useVisibilityChange (agent/skill wrappers) — Agent/skill-specific
visibility-change wiring
- useChatDraft() — Draft state, trimmed submit, Enter/Shift handling
- useChannelConnectToast() — Shows success/error toast from URL params
(platform/status)
- useStarterUserMessage() — Captures starter message from router state
and clears it
- useAutoScroll() — Ref that scrolls a div to bottom when dependency
changes
Supporting data hooks & mutations
- useAvailableAgentTools() — Computes filtered AgentTool[] with picker
allowlist filtering and selection state
- useAgentBuilderAllowedModels() — Returns filtered providers and models
given policy and availability
- useUpdateSkill() — React Query mutation wrapper for stored-skill
updates
- useDefaultVisibility() — Returns 'private' as default visibility
Domain utilities
- packages/playground/src/domains/builder.ts:
- useBuilderFilteredProviders(), useBuilderFilteredModels() — Filter
providers/models by BuilderModelPolicy
- isModelNotAllowedError() — Detects/normalizes MODEL_NOT_ALLOWED errors
- Re-exports: useBuilderModelPolicy, useBuilderPickerVisibility
---
## Notable implementation/test details
- Tests replace simple mocks with hoisted, comprehensive mocks for RBAC,
builder settings, LLM provider state, mutation hooks, and UI components.
- Autosave hooks use debouncing, request sequence refs to ignore stale
async results, retry and flush API, and brief "saved" display state
before returning to idle.
- useAutosaveSkill regenerates SKILL.md file content
(createInitialStructure/updateRootFolderName/updateNodeContent) before
sending updates.
- Visibility change flows use a reusable dialog hook that shows
success/error toasts and updates react-hook-form fields with
shouldDirty: false on success.
- Model policy shape change: allowed/default models now use modelId (was
model) — test expectations updated accordingly.
---
## Breaking changes / notes
- Model policy data shape updated from model → modelId for
allowed/default models (affects code/tests relying on prior shape).
- packages/playground typecheck still reports unrelated existing
TypeScript errors outside the scope of this work.
---
## Test command
pnpm exec vitest run
src/domains/agent-builder/hooks/__tests__/builder-hooks.test.tsx
--coverage.enabled --coverage.provider=v8
--coverage.include='src/domains/agent-builder/hooks/**/*.{ts,tsx}'
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16775?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
…r to Base UI (mastra-ai#16791) ## Summary - **Add `ContextMenu`** — new design system component built on `@base-ui/react/context-menu`. Namespaced API mirrors `DropdownMenu` (`Trigger`, `Content`, `Item`, `CheckboxItem`, `RadioItem`, `Label`, `Separator`, `Shortcut`, `Group`, `Sub`/`SubTrigger`/`SubContent`, `RadioGroup`, `Portal`). `Item` supports a `variant="destructive"`. Visual style matches `DropdownMenu` 1:1 via DS tokens. - **Migrate `DropdownMenu`** from `@radix-ui/react-dropdown-menu` to `@base-ui/react/menu`. Public API unchanged; `asChild` on `Trigger` is preserved via a render-prop shim. `Item` gains the same `variant` prop. No visual regressions. - **Migrate `Popover`** from `@radix-ui/react-popover` to `@base-ui/react/popover`. Public API unchanged; `HoverPopover` kept. Internal consumer `property-filter-creator` switched from Radix-only `onOpenAutoFocus`/`onCloseAutoFocus` to Base UI's `initialFocus`/`finalFocus`. - **Robustness** — `Label` no longer wraps Base UI's `GroupLabel` (which requires a `Group` ancestor and threw `MenuGroupRootContext is missing` when used standalone). It now renders a plain styled `<div>` matching Radix's previous behavior. Smoke tests force-mount every menu part in an open menu to catch any future Base UI context errors. - **Disabled items** show `cursor-not-allowed` and neutralize hover/focus/highlighted styles (instead of `pointer-events-none`, which suppressed the disabled cursor visual). ## Test plan - [x] `pnpm exec tsc --noEmit` on `@mastra/playground-ui` — exit 0 - [x] `pnpm exec tsc --noEmit` on `@mastra/playground` (consumer with ~273 usages) — exit 0 - [x] `pnpm build` on `@mastra/playground-ui` — OK - [x] `pnpm test` on `@mastra/playground-ui` — 191/191 (4 new smoke tests added) - [x] `pnpm lint` — 0 errors (warnings pre-existing) - [x] `pnpm exec prettier --check` on touched files — OK - [ ] Manual: open Storybook (`pnpm storybook`) and check `Elements/ContextMenu`, `Elements/DropdownMenu`, `Elements/Popover` — visual + interactions (right-click, hover, focus, sub, checkbox, radio, escape, disabled cursor, destructive) - [ ] Manual: app smoke test — PropertyFilter, DataFilter, DateTimePicker, traces list mode toggle (uses DropdownMenu/Popover) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR replaces Radix-based menus/popovers with a shared Base UI implementation, adds a new right-click ContextMenu, and fixes several focus/disabled/label edge-cases so menus and popovers behave more reliably without forcing consumers to change how they use them. ## What Changed **New Component: ContextMenu** - Adds ContextMenu built on `@base-ui/react/context-menu` with a namespaced API matching DropdownMenu (Trigger, Content, Item, CheckboxItem, RadioItem, Label, Separator, Shortcut, Group, Sub/SubTrigger/SubContent, RadioGroup, Portal). - Item supports variant="destructive". - Visual styling uses DS tokens. - Storybook stories (6) and smoke tests that mount every part in an open menu were added. **Migration: DropdownMenu** - Replaced `@radix-ui/react-dropdown-menu` with `@base-ui/react/menu`. - Public API preserved; Trigger keeps asChild via a render-prop shim. - Item gained inset/variant props (including destructive) and an onSelect alias for compatibility with prior Radix onSelect semantics. - Component props: added defaultOpen and retyped onOpenChange to MenuPrimitive.Root's type; Content/SubContent accept Base UI positioning props (align, alignOffset, side, sideOffset, container). - Smoke tests mount all parts open to surface compatibility/context issues. **Migration: Popover** - Replaced `@radix-ui/react-popover` with `@base-ui/react/popover`. - Public API kept; PopoverTrigger supports asChild via render-prop shim; HoverPopover preserved with updated prop typing. - PopoverContent now uses Base UI Positioner/Popup and data-[open]/data-[closed] state classes. - Focus handling moved from Radix onOpenAutoFocus/onCloseAutoFocus to Base UI initialFocus/finalFocus; PropertyFilter updated to set initialFocus={false} and use finalFocus to avoid unwanted focus return. **Robustness & Fixes** - Label renders a styled div instead of wrapping Base UI’s GroupLabel to avoid missing Group context errors. - Disabled items now use cursor-not-allowed and neutralize interaction styles (instead of pointer-events-none). - Menu.Item and ContextMenu.Item invoke onClick and onSelect (alias) so existing call sites using onSelect continue to work; regression tests added asserting both fire once. - Added comprehensive smoke tests for DropdownMenu and ContextMenu that mount every subcomponent with defaultOpen. **Changesets** - Patch/minor changesets documenting: ContextMenu addition (minor), DropdownMenu.Item variant (patch), and Popover focus-prop guidance (patch). ## Tests & CI - playground-ui types/build passed. - playground-ui tests: 191/191 (includes 4 new smoke tests). - Lint/Prettier checks passing. - Storybook stories added; manual Storybook/app visual checks listed as TODO. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16791?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…6803) ## Summary - remove DuckDB sequence-backed defaults from observability cursor columns and migrations - write sequence cursor IDs explicitly in span, log, metric, score, and feedback insert paths - add regression coverage that ensures cursor schema avoids defaults and a file-backed DuckDB database reopens after cursor migrations and cursor writes - add a patch changeset for @mastra/duckdb ## Why The delta polling migration introduced ALTER COLUMN cursorId SET DEFAULT nextval(...) for DuckDB observability tables. We reproduced that DuckDB can fail WAL replay after dev server hot reload with this catalog default. This keeps the delta polling behavior for new rows without relying on fragile column defaults. ## Test plan - pnpm --filter @mastra/duckdb test -- src/storage/domains/observability/index.test.ts --bail 1 --reporter=dot - pnpm --filter @mastra/duckdb typecheck - pnpm --filter @mastra/duckdb lint <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 DuckDB could crash after dev-server restarts because it relied on automatic cursor ID defaults in the DB. This PR removes those fragile defaults and makes the app explicitly generate and write cursor IDs on insert so databases reopen and WAL replay no longer fail. --- ## Overview Removes DuckDB sequence-backed DEFAULTs from observability cursorId columns, updates all observability write paths to explicitly generate and write cursor IDs using the corresponding sequences, adds a migration helper to drop legacy cursor defaults, and adds regression tests (including a file-backed reopen test). Also adds a patch changeset for `@mastra/duckdb`. ## Changes - DDL & migrations (stores/duckdb/src/storage/domains/observability/ddl.ts) - cursorId columns defined as nullable BIGINT with no DEFAULT nextval(...). - ALL_MIGRATIONS no longer sets column defaults; additive migrations add cursorId as BIGINT only. - Comments note that upgraded rows may have NULL cursorId and delta polling relies on explicit nextval() on writes. - Explicit cursor generation on insert paths - tracing.ts (span events): include cursorId in COLUMNS and inject nextval('span_events_cursor_id_seq') for inserted rows. - logs.ts (log events): add cursorId to COLUMNS and batch inserts use nextval('log_events_cursor_id_seq'). - metrics.ts (metric events): include cursorId and use nextval('metric_events_cursor_id_seq') in batch inserts. - scores.ts (score events): populate cursorId via nextval('score_events_cursor_id_seq') for single and batch inserts. - feedback.ts (feedback events): populate cursorId via nextval('feedback_events_cursor_id_seq') for single and batch inserts. - Migration helper & init changes - Added dropLegacyCursorIdDefaults(db) (migration.ts) that queries information_schema.columns and DROP DEFAULT for cursorId only when present. - ObservabilityStorageDuckDB.init() calls dropLegacyCursorIdDefaults(db) after applying DDL + migrations. - Tests & regression coverage (index.test.ts) - Test that combined DDL + migrations SQL contains no cursorId DEFAULT clauses. - Simulate legacy DB defaults via ALTER TABLE ... SET DEFAULT nextval(...) and assert init() removes them for observability tables. - Assert init() skips drop when no defaults exist by verifying expected executeBatch usage. - Integration: file-backed DuckDB DDL/migrations → insert rows using explicit nextval(...) cursor writes → close & reopen DB, asserting rows persist and reopen succeeds. - Changeset - .changeset/fluffy-melons-divide.md: patch bump for `@mastra/duckdb` documenting the fix. ## Reasoning & Impact - Reason: DuckDB catalog defaults (ALTER COLUMN ... SET DEFAULT nextval(...)) can cause WAL replay failures during dev hot reloads. Relying on them is fragile. - Impact: Prevents dev-server WAL replay crashes, preserves delta-polling behavior by ensuring new rows receive monotonically increasing cursor IDs via explicit nextval() calls, and provides a migration path to remove legacy defaults. ## Tests / Validation - New tests in stores/duckdb/src/storage/domains/observability/index.test.ts cover schema defaults removal, init behavior, and file-backed reopen after explicit cursor writes. - Recommended local checks included in PR: pnpm --filter `@mastra/duckdb` test ...; pnpm --filter `@mastra/duckdb` typecheck; pnpm --filter `@mastra/duckdb` lint. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16803?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai> Co-authored-by: Eric Pinzur <2641606+epinzur@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Eric Pinzur <epinzur@gmail.com>
…pages (mastra-ai#16813) ## Summary - Removed the `Primitives` and `Observability` overview pages (`/primitives`, `/observability-overview`). Each only rendered a static grid of links that already exist in the sidebar. After the studio shell refresh dropped their nav entries, both pages became unreachable from the UI, so this removes the pages, their routes in `App.tsx`, and the stale `sectionNav` entries. - Kept the `Evaluation` overview (`/evaluation`) — it is a real dashboard, still a sidebar item, and remains in `sectionNav` for breadcrumb resolution. - Dropped the redundant outer padding/sizing on the `RequestContextWrapper` (`p-5` + `h-full w-full overflow-y-auto`), which doubled the `PageLayout` root's `p-6` and created a nested scroll container. ## Test plan - [ ] `/request-context` renders with a single page inset and one scrollbar - [ ] Sidebar `Primitives` and `Observability` sections still work; their child links navigate correctly - [ ] Visiting `/primitives` or `/observability-overview` directly no longer resolves - [ ] `pnpm --filter @internal/playground lint` passes <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR cleans up the playground by removing two pages ("Primitives" and "Observability" overviews) that were just showing lists of links—the same links that are already easily accessible in the left sidebar. It also fixes some extra padding that was making the page layout look weird. ## Changes ### Removed Pages - Deleted the `Primitives` overview page (`/primitives`) which rendered a static grid of links to Agents, Prompts, Workflows, Processors, MCP Servers, Tools, Workspaces, and Request Context - Deleted the `Observability` overview page (`/observability-overview`) which displayed Metrics and Traces sections as a link grid ### Route and Navigation Updates - Removed imports and route definitions for both pages in `App.tsx` - Removed redundant `sectionNav` entries for `Observability` and `Primitives` overview routes - Kept the `Evaluation` overview (`/evaluation`) in `sectionNav` since it functions as a real dashboard with actual content ### Layout Improvements - Removed redundant styling (`h-full w-full overflow-y-auto p-5` classes) from `RequestContextWrapper` in the Request Context component, as this duplicated padding already applied by the parent `PageLayout` component and created an unnecessary nested scroll container ### Documentation - Updated comment in `app-sidebar.tsx` to clarify exact/sub-path matching behavior - Added changeset documentation for the removal and styling fix <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16813?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…-ai#16798) ## Summary The ClickHouse v-next observability discovery endpoints (tags, services, environments, entities, metric names, metric labels) were returning each distinct value multiple times. The refreshable materialized views that populate the `mastra_discovery_values` and `mastra_discovery_pairs` helper tables use `REFRESH EVERY ... TO <pre-created table>`, which in ClickHouse appends a fresh copy of its result set on every refresh. Because the helper tables were plain `MergeTree`, each refresh cycle layered on another full copy of every distinct value — so by the time a user hit `GET /observability/discovery/tags` they saw every tag once per refresh cycle that had run. This PR switches the helper tables to `ReplacingMergeTree` with `ORDER BY` covering every column so background merges collapse the byte-identical duplicate rows, reconciles existing deployments on startup by dropping and recreating any helper tables still on `MergeTree`, and keeps `SELECT DISTINCT` on the read side so results stay correct between refreshes and merges. Closes mastra-ai#16747 ## What changed - `ddl.ts` — `DISCOVERY_VALUES_DDL` and `DISCOVERY_PAIRS_DDL` now use `ReplacingMergeTree`. - `index.ts` — New `reconcileDiscoveryTables()` helper runs early in `init()`. It introspects `system.tables`; when a helper table is found on the old engine it drops the refreshable MV first (so it cannot write into the table mid-drop) then drops the table. The existing `CREATE TABLE IF NOT EXISTS` and discovery MV bootstrap then recreate both with the current definitions. No-op when the table is already on the expected engine or doesn't exist yet. - `discovery.ts` / `metrics.ts` — All discovery read queries use `SELECT DISTINCT`. `ReplacingMergeTree` only dedupes during background merges, so a row can briefly appear more than once between refresh cycles; `DISTINCT` over the `ORDER BY` columns is effectively free at this cardinality and keeps results stable regardless of merge timing. ## Testing - Added an automated integration test `init() reconciles pre-existing MergeTree discovery tables to ReplacingMergeTree` that creates an isolated database, manually provisions the helper tables as `MergeTree` to simulate a pre-fix deployment, runs `init()`, and asserts the tables are now `ReplacingMergeTree` and that both refreshable MVs were recreated. - The 9 existing `discovery` integration tests were tightened to assert uniqueness (`expect(result).toEqual([...new Set(result)])`) rather than just presence. A second discovery refresh was added to the test setup so duplicates would accumulate without the fix — verifying the test would actually catch the regression. - Verified the test suite fails as expected when `SELECT DISTINCT` is reverted, then passes again once restored. - Manually validated the migration path end-to-end against a ClickHouse 26.2 instance: provisioned the helper tables as `MergeTree`, ran `init()`, confirmed `system.tables` reported `ReplacingMergeTree` for both, and confirmed discovery reads still returned unique values after the refresh. - Full v-next test suite (170 tests) passing locally; lint and typecheck clean. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 The observability filters were showing the same values multiple times. This PR makes the DB helper tables automatically collapse duplicate rows, adds a startup step to upgrade old helper tables if present, and ensures queries only return unique values so the UI shows each value once. --- ## Problem Discovery endpoints (tags, services, environments, entities, metric names, metric labels) could return duplicate values because refreshable materialized views wrote into helper tables backed by MergeTree and duplicates could appear between MV refresh and background consolidation (issue `mastra-ai#16747`). ## Solution 1. Schema (DDL) - Changed discovery helper tables (`DISCOVERY_VALUES_DDL`, `DISCOVERY_PAIRS_DDL`) from MergeTree to ReplacingMergeTree and added ORDER BY covering all logical columns so background merges collapse byte-identical duplicates. 2. Runtime reconciliation - Added reconcileDiscoveryTables(client), invoked early in init(), which inspects system.tables and: - Uses the existing isReplacingMergeTreeEngine() helper to accept Shared/Replicated/*ReplacingMergeTree variants as already migrated, - If a helper table uses a legacy engine, drops dependent refreshable MV(s) first, drops the table, and lets subsequent CREATE TABLE IF NOT EXISTS + MV bootstrap recreate them with ReplacingMergeTree. - Silently no-ops if tables are absent or already correct. 3. Read-side stability - Discovery and metrics read queries updated to use SELECT DISTINCT for returned value fields (getEntityTypes, getEntityNames, getServiceNames, getEnvironments, getTags, metric names/label keys/values) so results remain unique between MV refresh and ReplacingMergeTree background merges. ## Notable implementation & test details - reconcileDiscoveryTables reuses isReplacingMergeTreeEngine() to correctly recognize Shared/Replicated ReplacingMergeTree variants and avoid unnecessary drops. - Tests were strengthened to model the real intermediate window: after MV refresh the suite injects duplicate rows (INSERT INTO t SELECT * FROM t) to ensure duplicates exist on disk before ReplacingMergeTree merges, and assertions require unique outputs (via new Set). Reverting the DISTINCT in reads causes tests to fail as expected. - The migration/reconcile test pre-creates helper tables with MergeTree and refreshable MVs pointing at them so the MV-drop branch is exercised end-to-end. - Verified locally against ClickHouse 26.2.x; full v-next test suite passes; lint and typecheck are clean. ## Files changed (high level) - .changeset/shaky-needles-dance.md — changelog entry - stores/clickhouse/src/storage/domains/observability/v-next/ddl.ts — helper tables changed to ReplacingMergeTree with full ORDER BY - stores/clickhouse/src/storage/domains/observability/v-next/index.ts — added reconcileDiscoveryTables() and wired into init(), imported isReplacingMergeTreeEngine - stores/clickhouse/src/storage/domains/observability/v-next/discovery.ts & metrics.ts — queries updated to SELECT DISTINCT - stores/clickhouse/src/storage/domains/observability/v-next/index.test.ts & migration.test.ts — integration & migration tests strengthened to seed duplicates and validate reconciliation ## Tests & verification - New integration test verifies pre-existing MergeTree helper tables + refreshable MVs are reconciled to ReplacingMergeTree and MVs recreated. - Discovery tests seed duplicate rows and assert uniqueness; they fail if DISTINCT is removed. - Verified locally against ClickHouse 26.2.x; v-next test suite, lint, and typecheck pass. Closes issue `mastra-ai#16747`. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16798?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
## Summary - Migrates the `Dialog` design system component from `@radix-ui/react-dialog` to `@base-ui/react/dialog`. - **Public API unchanged.** `asChild` on `DialogTrigger` and `DialogClose` is preserved through a render-prop shim (same pattern as the `Popover`/`DropdownMenu` migrations). All exports kept: `Dialog`, `DialogTrigger`, `DialogClose`, `DialogPortal`, `DialogOverlay`, `DialogContent`, `DialogHeader`, `DialogFooter`, `DialogBody`, `DialogTitle`, `DialogDescription`. - Part mapping: Radix `Overlay` → Base UI `Backdrop`, `Content` → `Portal` + `Popup`. - `dialog.css` now matches both `data-open`/`data-closed` (Base UI) and `data-state` (Radix) so the shared stylesheet keeps animating `AlertDialog`, which is still on Radix. - `CommandDialog` props narrow `children` to `ReactNode` — Base UI's `Dialog.Root` widens `children` with a payload render-function overload that `cmdk` can't accept. - Adds `dialog.test.tsx` smoke tests: mounts every part in an open dialog, verifies the `asChild` shim, trigger open, and `onOpenChange` on both the built-in close button and an `asChild` `DialogClose`. ## Test plan - [x] `pnpm exec tsc --noEmit` on `@mastra/playground-ui` — exit 0 - [x] `pnpm exec tsc --noEmit` on `@mastra/playground` (consumer, ~30 dialog files) — exit 0 - [x] `pnpm build` on `@mastra/playground-ui` — OK - [x] `pnpm test` on `@mastra/playground-ui` — 200/200 (5 new) - [x] `eslint` on `Dialog` + `Command` — clean - [ ] Manual visual check of open/close animations in Studio (not run — dev server lives on the main checkout) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR swaps the Dialog component's underlying library from Radix UI to Base UI while keeping the same public API and behavior — like replacing an engine but leaving the steering and controls unchanged. --- ## Overview Migrates the Dialog design-system component from `@radix-ui/react-dialog` to `@base-ui/react/dialog` while preserving public exports, asChild behavior, and the visual open/close animations so consumers are unaffected. ## Changes ### Core Migration - Replaced Radix Dialog primitives with Base UI primitives (imported from `@base-ui/react/dialog`). - Kept public exports: Dialog, DialogTrigger, DialogClose, DialogPortal, DialogOverlay, DialogContent, DialogHeader, DialogFooter, DialogBody, DialogTitle, DialogDescription. - Mapped Radix concepts to Base UI equivalents: Radix Overlay → Base UI Backdrop; Radix Content → Base UI Portal + Popup. ### asChild Shim & Component Wrappers - DialogTrigger and DialogClose implemented as explicit React.forwardRef wrappers that preserve asChild by passing Base UI's render-prop when children is a valid element (same shim pattern used for Popover/DropdownMenu). - DialogOverlay and DialogContent are forwardRef wrappers around Base UI Backdrop/Popup with local prop typings and className handling. - DialogContent includes the built-in close button using the primitive Close's render prop (Button with X icon). ### Styling - dialog.css updated so overlay/content animations respond to both Radix data-state (open/closed) and Base UI data-open/data-closed attributes; existing keyframes and animation timings retained so AlertDialog (still on Radix) and the new Dialog share animations. ### Props & Typing - CommandDialog props narrowed: children is now React.ReactNode (Omit of Dialog props with children reintroduced) to avoid Base UI Dialog.Root's render-function overload conflicting with cmdk. ### Tests - Added dialog.test.tsx (Vitest + React Testing Library) covering: - Mounting every dialog part inside an open dialog. - DialogTrigger asChild renders child without nested button. - Clicking trigger opens dialog. - onOpenChange called with false when closing via built-in close button and via an asChild DialogClose. - 5 new tests added; test suite passes locally. ## Validation - Type-check: pnpm exec tsc --noEmit for `@mastra/playground-ui` and `@mastra/playground` — passed. - Build: `@mastra/playground-ui` builds successfully. - Tests: all tests passing (includes the 5 new tests). - ESLint: Dialog and Command files lint-clean. - Manual visual check of open/close animations: not run. ## Notes for reviewers - Focus review on dialog.tsx wrapper implementations (asChild render-prop shims), dialog.css selector additions, and the CommandDialog props change that tightens children to ReactNode. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16821?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `main` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `main`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## @mastra/playground-ui@29.0.0-alpha.9 ### Patch Changes - Moved the `Dialog` component to Base UI. The public API is unchanged — `asChild` on `DialogTrigger` and `DialogClose` still works the same way, and open/close animations behave as before. ([mastra-ai#16821](mastra-ai#16821)) ## @mastra/clickhouse@1.9.0-alpha.1 ### Patch Changes - Fixed duplicate entries in the ClickHouse v-next observability discovery endpoints — tags, services, environments, entities, metric names, and metric labels now return each value once. Existing deployments are reconciled automatically on next startup; no manual migration required. ([mastra-ai#16798](mastra-ai#16798)) ## mastra@1.9.4-alpha.9 ## create-mastra@1.9.4-alpha.9 ## @internal/playground@1.9.4-alpha.9 ### Patch Changes - Removed the unused Primitives and Observability overview pages from the studio. These pages only showed links that already exist in the sidebar, so they were redundant and no longer reachable from the navigation. Also fixed extra padding around the Request Context page content. ([mastra-ai#16813](mastra-ai#16813)) - Updated dependencies \[[`b699688`](mastra-ai@b699688)]: - @mastra/playground-ui@29.0.0-alpha.9 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
mastra-ai#16808) ## Summary The in-memory observability storage in `@mastra/core` had its own bespoke test file that duplicated coverage every vNext storage adapter needs. This PR extracts those tests into a shared `createObservabilityVNextTests` factory in `@internal/storage-test-utils`, so the in-memory store and DuckDB now both validate against the same 46 portable contract tests. Running that shared suite against in-memory surfaced four real behavior bugs in `ObservabilityInMemory`, which are also fixed here. ## What changed **Shared vNext observability suite (`@internal/storage-test-utils`)** - New `createObservabilityVNextTests({ getStorage, capabilities })` factory at `stores/_test-utils/src/domains/observability-vnext/`. - The factory is invoked against `MockStore` from `_test-utils/src/index.test.ts`, giving InMemoryStore continuous contract coverage with no `@mastra/core` devDep coupling. - `stores/duckdb` calls the same factory from its own observability test file alongside its bespoke event-sourced / DDL / lazy-store tests. **`@mastra/core` observability InMemory** - `getSpans` now batch-fetches spans by id within a trace (previously threw "not supported"), enabling the optimized `getBranch` path. - `batchCreateLogs`, `batchCreateMetrics`, `createScore`/`batchCreateScores`, `createFeedback`/`batchCreateFeedback` now upsert by id instead of appending duplicates on retry, preserving cursor ids so delta polling does not re-emit the record. - Discovery (`getEntityTypes`, `getEntityNames`, `getServiceNames`, `getEnvironments`, `getTags`) now scans logs and metrics in addition to spans. - `getMetricTimeSeries` keys grouped series on the label tuple instead of a `|`-joined string, so series whose display names collide (e.g. `{segmentA: 'a', segmentB: 'b|c'}` vs `{segmentA: 'a|b', segmentB: 'c'}`) remain distinct. **Tests** - Deleted `packages/core/src/storage/domains/observability/inmemory.test.ts`; the 34 contract tests live in the factory now. - The two `extractBranchSpans` helper unit tests moved into `packages/core/src/storage/domains/observability/tracing.test.ts` next to the helper they cover. ## Test plan - `pnpm --filter @mastra/core vitest run src/storage/domains/observability` — 155 tests pass (7 files). - `pnpm --filter @internal/storage-test-utils vitest run` — 547 tests pass (factory 46 + the rest of the domain factories against MockStore). - `pnpm --filter @mastra/duckdb-store vitest run src/storage/domains/observability` — 125 tests pass (119 in `index.test.ts`: 60 bespoke event-sourced/infra tests + 59 factory tests). 🤖 Generated with [Mastra Code](https://mastra.ai/code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR creates one shared checklist of observability tests that every storage implementation must pass, then fixes bugs in the in-memory storage so it passes the same suite as the DuckDB store. ## Overview Consolidates vNext observability contract tests into a portable factory (createObservabilityVNextTests) in `@internal/storage-test-utils` and runs that factory against MockStore and DuckDB to provide a 46-test (portable) contract suite. The change removes duplicate per-package observability tests, lowers test-maintenance burden, and uncovered/fixed behavioral bugs in the in-memory adapter. ## Changes ### New Test Factory & Utilities - stores/_test-utils/src/domains/observability-vnext/index.ts - Adds createObservabilityVNextTests with ObservabilityVNextCapabilities and CreateObservabilityVNextTestsOptions to produce a comprehensive 46+ test suite covering delta polling, cursor pagination, batch operations, retry idempotency (upsert-by-id), discovery endpoints, aggregation/breakdown/time-series shapes, and collision-resistant metric grouping. - stores/_test-utils/src/domains/observability-vnext/data.ts - Adds VNEXT_BASE_DATE and makeSpan for deterministic span fixtures; re-exports EntityType and SpanType. - stores/_test-utils/src/index.ts and index.test.ts - Re-exports and wires the shared factory; runs the suite against MockStore with fresh store instances per test. ### In-Memory Storage Fixes - packages/core/src/storage/domains/observability/inmemory.ts - Added getSpans to support batch span retrieval by id within a trace (enables optimized getBranch path). - Introduced upsertByIdField helper and switched batchCreateLogs, batchCreateMetrics, createScore/batchCreateScores, createFeedback/batchCreateFeedback to upsert-by-id to avoid duplicates on retry and preserve cursor ids. - Expanded discovery APIs (getEntityTypes, getEntityNames, getServiceNames, getEnvironments, getTags) to scan logs and metrics in addition to spans. - Fixed getMetricTimeSeries to group series by the original label tuple (not a `|`-joined string) to avoid key collisions. ### Tests & Consolidation - Removed packages/core/src/storage/domains/observability/inmemory.test.ts (now covered by the shared factory). - Moved two extractBranchSpans unit tests into packages/core/src/storage/domains/observability/tracing.test.ts to keep focused unit coverage. ### DuckDB Adapter Integration - stores/duckdb/src/storage/domains/observability/index.test.ts - Registers the shared factory for DuckDB observability (capabilities: label 'DuckDB', preferredStrategy 'event-sourced'), reusing existing setup/teardown. ### Commit/Typing Adjustments - Various commits adjust TypeScript types and test fixtures to ensure downstream consumers compile (nominal enums, labels: {}, narrower log level types, optional/null toleration) and minor housekeeping (drops changeset, test fixture tweaks). ### Documentation - .changeset/yummy-lions-act.md documents the in-memory observability behavioral fixes (batch span fetch, upsert semantics, discovery scope expansion, metric series keying). ## Test Results - `@mastra/core` observability: 155 tests pass - `@internal/storage-test-utils`: 547 tests pass (including 46 factory tests) - `@mastra/duckdb-store` observability: 125 tests pass (59 factory tests + bespoke tests) ## Impact Establishes a portable, shared vNext observability test contract, reduces duplicated test maintenance and cross-package devDep coupling, and fixes in-memory storage behaviors (batch span retrieval, idempotent upserts, expanded discovery, and robust metric grouping) discovered by running the shared suite. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16808?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
## Summary The Filter menu on the Agent **Review** page (and Dataset Review) crashed with `\`MenuPortal\` must be used within \`Menu\``. **Root cause:** the recent migration of `DropdownMenu` to Base UI (mastra-ai#16791). Three files still imported `Portal`/`SubContent` directly from `@radix-ui/react-dropdown-menu` and rendered them inside the now Base-UI `DropdownMenu`. The Radix `Portal` looks up the Radix `Menu` context, which no longer exists → crash. **Fix:** replace the local `PortalSubContent` helper with the design system's `DropdownMenu.SubContent` (already Base UI `Portal` + `Positioner` + `Popup`). Files: - `packages/playground-ui/.../DataFilter/select-data-filter.tsx` - `packages/playground/.../agent-playground/agent-playground-review.tsx` - `packages/playground/.../review/components/dataset-review.tsx` Also memoized a pre-existing non-memoized `items` value in `dataset-review.tsx` to satisfy the lint gate (behavior unchanged). **Scope check:** grepped the whole repo — no remaining direct imports of `@radix-ui/react-dropdown-menu` / `react-popover` / `react-context-menu`, no use of the removed Popover `onOpenAutoFocus`/`onCloseAutoFocus` props, and every `DropdownMenu.Sub*` usage sits inside a valid `DropdownMenu` root. These three files were the only source of this error class. ## Test plan - [ ] Agents -> an agent -> **Review** tab -> **Filter** -> hover **Status** / **Tags** submenus — opens without crashing - [ ] Datasets -> a dataset -> **Review** -> **Filter** -> hover **Status** / **Tags** submenus - [ ] Verify menu items (checkboxes, radio, clear-all) still work <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Filter menus were breaking on the Agent and Dataset review pages with an error about "MenuPortal must be used within Menu." This happened because the code was trying to use old dropdown menu components (from Radix UI) with a new dropdown menu system (Base UI), which don't work together. The fix was simple: replace those old components with the correct new versions from the design system. --- ## Problem Filter menus on the Agent Review and Dataset Review pages were crashing with the error "MenuPortal must be used within Menu" after `DropdownMenu` was migrated from Radix UI to Base UI. ## Root Cause Three files were still importing `Portal`/`SubContent` directly from `@radix-ui/react-dropdown-menu` and rendering them inside the Base UI `DropdownMenu`. The Radix `Portal` component depended on Radix `Menu` context, which no longer exists after the migration. ## Solution Replaced the custom `PortalSubContent` helper component with the design system's `DropdownMenu.SubContent` component (which properly composes Base UI `Portal` + `Positioner` + `Popup`). ## Changes Made **Modified files:** - `packages/playground-ui/src/ds/components/DataFilter/select-data-filter.tsx` — Removed custom `PortalSubContent` wrapper; submenu content now uses `DropdownMenu.SubContent` - `packages/playground/src/domains/agents/components/agent-playground/agent-playground-review.tsx` — Replaced Radix-based `PortalSubContent` with `DropdownMenu.SubContent` in Status and Tags nested dropdowns - `packages/playground/src/domains/review/components/dataset-review.tsx` — Removed custom Radix Portal-based helper; switched submenu content to use `DropdownMenu.SubContent`; memoized `items` value to satisfy linting requirements **Added:** - `packages/playground-ui/.changeset/cute-buckets-prove.md` — Changeset documenting the patch fix ## Validation Repository-wide grep confirms no remaining direct imports of deprecated Radix UI dropdown menu components; all `DropdownMenu.Sub*` usage is within valid `DropdownMenu` roots. The three modified files were the only sources of this error class. ## Testing - Agent Review page: open an agent → Review → Filter → hover Status/Tags submenus (should open without crashing) - Dataset Review page: open a dataset → Review → Filter → hover Status/Tags submenus (should open without crashing) - Menu items (checkboxes, radio, clear-all) continue to function correctly <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16829?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - Bumps `@base-ui/react` from `^1.3.0` to `^1.5.0` in `@mastra/playground-ui`. - Pure dependency upgrade — no API or component changes. ## Note Draft until the `pnpm-lock.yaml` update lands. `@base-ui/react@1.5.0` was published <24h ago and is currently blocked by the repo's `minimumReleaseAge` gate (1 day). The lockfile commit will be pushed once the gate passes (~1h after opening), at which point this can be marked ready. ## Test plan - [ ] `pnpm install --filter @mastra/playground-ui` updates lockfile cleanly - [ ] `pnpm build` on `@mastra/playground-ui` — passes <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR upgrades a UI helper library (Base UI) used by the playground from version 1.3 to 1.5 so popup components open/close faster; it's a safe dependency bump with no API changes. ## Overview - Bumps `@base-ui/react` from ^1.3.0 to ^1.5.0 in packages/playground-ui. - Adds a changeset to publish a patch release for `@mastra/playground-ui` documenting the upgrade and popup performance improvements. - No exported/public API changes. ## Changes - packages/playground-ui/package.json: dependency updated to "`@base-ui/react`": "^1.5.0" - .changeset/metal-boats-walk.md: notes patch release and improved popup open/close performance ## Status Notes - PR is currently draft. `@base-ui/react`@1.5.0 was published <24h ago and the repo enforces a minimumReleaseAge gate (1 day). The pnpm lockfile update has not been committed yet; it will be added once the gate passes (≈1 hour after opening), at which point the PR can be marked ready. ## Testing - Expected checklist: - pnpm install --filter `@mastra/playground-ui` updates lockfile cleanly (lockfile commit pending gate) - pnpm build on `@mastra/playground-ui` — should pass (no source changes) <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16819?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Upgrades pi-tui so MastraCode picks up its throttled render scheduler. This keeps the tui from locking up while large tool previews stream in, especially big edit/write previews. Also updates our keybinding calls for the newer pi-tui API: ```ts getEditorKeybindings() ``` becomes: ```ts getKeybindings() ``` and select actions now use the namespaced IDs like `tui.select.up`. Tested with a large streamed edit, plus: ```bash pnpm --filter mastracode check pnpm --filter mastracode lint ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR makes MastraCode's terminal display faster and more responsive when showing large previews by upgrading a library component. It also updates how keyboard shortcuts work in the interface to match the latest version of that library. ## Overview This PR upgrades the `@mariozechner/pi-tui` dependency from `^0.60.0` to `^0.73.1` to improve terminal UI rendering responsiveness. The upgrade includes a throttled render scheduler that prevents the TUI from freezing when large tool previews stream in. Additionally, the PR updates all TUI components to use the new keybinding API introduced in the newer version. ## Key Changes ### Dependency Update - Upgraded `@mariozechner/pi-tui` from `^0.60.0` to `^0.73.1` in `mastracode/package.json` ### Keybinding API Migration All TUI components have been updated to use the new keybinding API: - Replaced `getEditorKeybindings()` calls with `getKeybindings()` - Updated keybinding action identifiers to use the new namespaced format (e.g., `tui.select.up`, `tui.select.down`, `tui.select.confirm`, `tui.select.cancel`) ### Updated Components The following components were updated to use the new keybinding API: - `api-key-dialog.ts` - `ask-question-dialog.ts` - `ask-question-inline.ts` - `goal-cycles-dialog.ts` - `login-dialog.ts` - `login-mode-selector.ts` - `login-selector.ts` - `mcp-selector.ts` - `model-selector.ts` - `plan-approval-inline.ts` - `thread-selector.ts` - `tool-approval-dialog.ts` ### Test Updates - Updated vitest mocks in `ask-question-inline-multiline.test.ts` and `thread-selector.test.ts` to use the new `getKeybindings()` API and namespaced action identifiers ### Changeset Added a changeset entry documenting the improvement to MastraCode rendering responsiveness during large streamed tool previews. ## Testing Changes were tested with large streamed edits and validated by running: - `pnpm --filter mastracode check` - `pnpm --filter mastracode lint` <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16835?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
## Summary - Migrates the `AlertDialog` design system component from `@radix-ui/react-alert-dialog` to `@base-ui/react/alert-dialog`. - **Public API unchanged.** `asChild` on `AlertDialog.Trigger` is preserved through a render-prop shim. `AlertDialog.Action` and `AlertDialog.Cancel` map to Base UI's `Close` part, keeping their styling and close-on-click behavior. - Part mapping: Radix `Overlay` → Base UI `Backdrop`, `Content` → `Portal` + `Popup`, `Action`/`Cancel` → `Close`. - Adds `alert-dialog.test.tsx` smoke tests: mounts every part open, verifies the `asChild` shim, trigger open, and `onOpenChange` via `Action` (plus its `onClick`) and `Cancel`. ## Stacked PR > Based on `feat/dialog-base-ui` (mastra-ai#16821), not `main`. `AlertDialog` shares `dialog.css` with `Dialog`; the Dialog PR adds the `data-open`/`data-closed` selectors that Base UI relies on. Review/merge mastra-ai#16821 first — GitHub will retarget this PR to `main` automatically once it lands. ## Test plan - [x] `pnpm exec tsc --noEmit` on `@mastra/playground-ui` — exit 0 - [x] `pnpm exec tsc --noEmit` on `@mastra/playground` — exit 0 - [x] `pnpm build` on `@mastra/playground-ui` — OK - [x] `pnpm test` on `@mastra/playground-ui` — 205/205 (5 new) - [x] `eslint` + `prettier` on `AlertDialog` — clean - [ ] Manual visual check of open/close animations in Studio (not run — dev server lives on the main checkout) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR replaces the underlying dialog implementation for AlertDialog from Radix UI to Base UI so internals use a different library, but from a developer/user perspective the dialog works the same as before. --- ## Summary **Migration of AlertDialog component from Radix UI to Base UI** This PR migrates the `AlertDialog` component in `@mastra/playground-ui` from `@radix-ui/react-alert-dialog` to `@base-ui/react/alert-dialog`. The external API remains backward compatible. ### Key Changes - Replaces Radix primitives with Base UI equivalents: - Radix Overlay → Base UI Backdrop - Radix Content → Base UI Portal + Popup - Radix Action/Cancel → Base UI Close (preserving close-on-click) - AlertDialogTrigger: now a React.forwardRef wrapper that implements an asChild render-prop shim to preserve previous asChild behavior (avoids extra DOM nesting). - AlertDialogOverlay / AlertDialogContent: refactored to use Base UI primitives and updated prop typings; `AlertDialogContent.displayName` set explicitly to 'AlertDialogContent'. - AlertDialogTitle / AlertDialogDescription: prop typings refactored to use Omit<...Props, 'className'> for consistency. - AlertDialogAction / AlertDialogCancel: now wrap Base UI Close primitive and preserve Action onClick behavior while ensuring onOpenChange is called when closing. ### Tests - Adds alert-dialog.test.tsx (Vitest + React Testing Library) that: - Mounts all parts open without errors - Verifies asChild shim avoids nested button - Opens the dialog via the trigger - Confirms onOpenChange(true/false) behavior and that Action’s onClick is invoked when Action closes the dialog ### Styling & Stacking - Reuses `dialog.css` and relies on data-open/data-closed selectors introduced in the companion Dialog Base UI migration (PR `mastra-ai#16821`). Review/merge `mastra-ai#16821` first. - Manual visual check of animations was not performed. ### Status - Type-checks and builds pass for `@mastra/playground-ui` and `@mastra/playground`. - Local build/tests for `@mastra/playground-ui` passed (205/205 tests; 5 new). - ESLint and Prettier clean for AlertDialog. ### Breaking Changes - None. Public API behavior is preserved (including Trigger.asChild and close behavior of Action/Cancel). <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16824?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - Migrates the `Collapsible` design system component from `@radix-ui/react-collapsible` to `@base-ui/react/collapsible`. - **Public API unchanged.** `asChild` on `CollapsibleTrigger` is preserved through a render-prop shim. `Collapsible` and `CollapsibleContent` keep the same props. - Part mapping: Radix `Root`/`Trigger`/`Content` → Base UI `Root`/`Trigger`/`Panel`. - **Smoother animation.** `CollapsibleContent` now animates with Base UI's height-based transition (`--collapsible-panel-height`) instead of the previous fade + slide, so the panel expands and collapses by actual height. - Chevron rotation moves from Radix's `data-state=open` to Base UI's `data-panel-open` on the trigger. - Adds `collapsible.test.tsx` smoke tests: mounts trigger + content open, verifies the `asChild` shim, and trigger toggle. ## Test plan - [x] `pnpm exec tsc --noEmit` on `@mastra/playground-ui` — exit 0 - [x] `pnpm exec tsc --noEmit` on `@mastra/playground` — exit 0 - [x] `pnpm build` on `@mastra/playground-ui` — OK - [x] `pnpm test` on `@mastra/playground-ui` — 198/198 (3 new) - [x] `eslint` + `prettier` on `Collapsible` — clean - [ ] Manual visual check of the height animation in Studio (not run — dev server lives on the main checkout) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR replaces the underlying library for the Collapsible component (Radix → Base UI) while keeping the developer-facing API the same. The panel now expands/collapses by actual height for a smoother animation instead of the previous fade+slide. ## Changes ### Component Implementation (`collapsible.tsx`) - Reimplemented Collapsible using `@base-ui/react/collapsible` (Root → Root, Trigger → Trigger, Content → Panel). - Preserved public API: `Collapsible`, `CollapsibleTrigger`, `CollapsibleContent` props unchanged and `asChild` support preserved via a render-prop shim on `CollapsibleTrigger`. - Animation: replaced Radix fade+slide with Base UI height-based transition using CSS variable `--collapsible-panel-height` and explicit starting/ending height rules (`h-0`) for smooth expand/collapse. - Layout fix: introduced an inner wrapper inside the Panel so consumer padding/margin/border do not break the height animation (prevents jump-to-0 issues). - Chevron rotation/triggers updated to use Base UI’s `data-panel-open` on the trigger (replaces Radix `data-state=open`). - Updated component display names and forwardRef signatures to match Base UI element types. ### Tests (`collapsible.test.tsx`) - Added three smoke tests: - mounting an open Collapsible renders trigger + content, - `asChild` renders a provided button element directly (no nested buttons), - clicking the trigger toggles content visibility. - Test run: `@mastra/playground-ui` tests pass (198/198, includes 3 new tests). ## Public API - No breaking changes: props and `asChild` behavior remain compatible with prior Radix-based implementation. ## Validation - Type checks and builds for `@mastra/playground-ui` and `@mastra/playground` complete per checklist. - ESLint and Prettier clean for Collapsible. - Manual visual check in Studio not performed in this branch. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16825?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Description Adds a Playground `tsc --noEmit` typecheck script and wires it into the Quality Assurance workflow so TypeScript errors are caught outside the Vite/esbuild build. Fixes the Playground type errors exposed by the new gate, including route/component props, dataset editor payload typing, memory/template/runtime typing, and shared Playground UI declaration props. Validated with Playground typecheck, Playground lint, Playground UI lint, Playground UI build, and `git diff --check`. ## Related Issue(s) Fixes mastra-ai#15972 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [x] Test update ## Checklist - [x] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR makes the Playground run TypeScript's full type checker in CI so TypeScript mistakes are caught before merging, and fixes the type errors the new check found across Playground, Playground UI, client, and server types. --- ## Overview Adds a Playground `typecheck` script (tsc --noEmit), wires it into CI (lint workflow + Turborepo), and backfills ~50+ TypeScript fixes so the Playground typecheck passes. Updates shared Playground UI types and related client/server schemas/types to keep the codebase type-safe. ## CI / Workflow - .github/workflows/lint.yml: Adds a Typecheck step that runs `pnpm turbo --filter ./packages/playground typecheck`. - turbo.json: Adds a `typecheck` task (dependsOn: ["^build"]). - packages/playground/turbo.json: Playground build now depends on `typecheck`. ## Build / Typecheck config - packages/playground/package.json: Adds `"typecheck": "tsc --noEmit -p tsconfig.typecheck.json"` and some @types dev deps. - packages/playground/tsconfig.typecheck.json: New config extending tsconfig.app.json and excluding stories/tests. ## Type & Component Fixes - Standardized React type usage (use of `import type`, ReactNode, CSSProperties, HTMLAttributes/ThHTMLAttributes). - Playground UI component prop typings updated: Table, Txt (adds optional title), Icon, and others. - Normalized handlers and signatures (CodeEditor onChange accepts string|undefined -> '' conversion; explicit MouseEvent and boolean typings; LoaderFunctionArgs for route loaders). - Swapped some local component imports to `@mastra/playground-ui` types (SchemaField) to centralize types. - Minor UI/typing adjustments across many Playground components (memoization, error normalization, prop additions). ## Data / Domain Typing Changes - Introduced `expectedTrajectory` into dataset item types and history/hooks; dataset edit/save flow updated to parse/submit it conditionally. - Template components: added optional props (imageURL, runId, workflowInfo, linkComponent). - Observational memory logic refined: an `observationalMemory` object is treated as enabled unless explicitly `enabled: false`. ## API / Client / Server typings - packages/server/src/server/schemas/agents.ts: providerSchema extended with `envVar: string | string[]`, `connected: boolean`, optional `docUrl`, and `models: string[]`. - packages/server/src/server/schemas/datasets.ts: itemVersionResponseSchema adds `expectedTrajectory?: unknown`. - client-sdks/client-js: widened `Provider.envVar` and added `expectedTrajectory?: unknown` in generated/handwritten types. ## Release / Changesets - Changesets updated to publish patch bumps for @mastra/playground-ui, @mastra/client-js, @mastra/server, and related internal packages. ## Miscellaneous - Removed unused PDF extraction stub. - Small nonfunctional tweaks (ScorerVersionCombobox variant, minor refactors). - Validated by: Playground typecheck, Playground lint, Playground UI lint, Playground UI build, and `git diff --check`. ## Related Issue Fixes mastra-ai#15972 <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ward Peeters <ward@coding-tech.com>
…uto-suspend, consolidate to single path (mastra-ai#16805) Co-authored-by: Abhi Aiyer <abhi@mastra.ai> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
…#16517) ## Summary Migrates `AgentChannels` from per-message `agent.stream()` calls to the new agent signals API. Each Mastra thread now shares a single `agent.subscribeToThread()` subscription, and incoming platform messages are delivered as `user-message` signals via `agent.sendSignal()`. The previous design started a fresh `agent.stream()` for every inbound message, which meant two messages arriving close together on the same channel thread could spawn concurrent runs and produce interleaved or duplicated output. With signals, a message that arrives while the agent is already running is queued into the existing run instead of kicking off a new one. ## What changed - **`processChatMessage`** — replaces `agent.stream(...)` with `ensureThreadSubscription()` + `agent.sendSignal(...)`. The signal carries the user's text (and any inline file parts) as a `CoreUserMessage`, with platform context attached via `requestContext`, signal `attributes`, and signal `metadata`. - **`ensureThreadSubscription`** — lazily opens one `agent.subscribeToThread()` per Mastra thread and caches the wrapped async iterable. Consumer errors evict the cache entry and unsubscribe. - **`consumeAgentStream`** — now accepts an `AsyncIterable<AgentChunkType>`, resets per-run rendering state (`toolCalls`, `seedApprovalContext`) on `finish` / `error` / `abort`, and filters out `data-*` signal echoes so we don't double-render the user's own message. - **Tool approval resume** — the resumed stream is discarded; rendering is driven entirely by the cached thread subscription. Approval card metadata is seeded into `pendingApprovalCards` so the existing card is edited (not duplicated) when `tool-result` chunks arrive. - **`buildEventContext` helper** — consolidates the `ChannelContext` / `attributes` / `signalMetadata` triple that was previously hand-rolled at both the message and tool-approval call sites. Each shape has a distinct audience (input processors, the LLM, and stream/storage consumers respectively), so all three are preserved. - **`AgentChannels.close()`** — unsubscribes all cached subscriptions and clears approval state for graceful shutdown. - **Docs** — small accuracy fix in `reference/agents/channels.mdx` (the page previously described the now-replaced `agent.stream()` path). ## Behavior change Follow-up messages on a busy thread now deliver into the active run instead of starting a new one. This is the intended fix for the conflict scenario but is worth flagging for anyone who was relying on the old "always start a new stream" behavior. ## Test plan - `pnpm --filter ./packages/core vitest run channels` — all 84 channel tests pass, including three new tests covering `close()` semantics (clears cached subscriptions, safe when none exist, swallows individual unsubscribe errors). - `pnpm --filter ./packages/core typecheck` — clean. - Manual smoke test against a Slack bot: back-to-back DMs, mention in a channel, and a tool-approval round-trip all render correctly via the shared subscription. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Instead of starting a brand-new agent run for every incoming message (which could make replies overlap or duplicate), the system now keeps one shared agent subscription per chat thread and sends new messages into that single running flow so replies stay ordered and consistent. ## Changes Overview Migrates AgentChannels from spawning agent.stream() per inbound message to using the agent signals API with a cached, per-Mastra-thread agent.subscribeToThread() consumer. Platform messages are delivered as `user-message` signals via agent.sendSignal(); messages that arrive while a run is active are queued into the existing run instead of starting concurrent streams. ## Key Changes - Thread subscription caching: ensureThreadSubscription() lazily creates and caches a wrapped agent.subscribeToThread() per mastraThreadId (uses a placeholder to avoid races); consumer errors evict the cache and unsubscribe. - Signal-based routing: processChatMessage() composes signal-ready text + eligible file/link parts (respects inlineMedia/inlineLinks), refreshes the Mastra thread snapshot, ensures the thread subscription, and sends the user message with agent.sendSignal() (uses ifIdle wake behavior and conditional auto-resume). - Stream consumer: consumeAgentStream(AsyncIterable<AgentChunkType>) consumes chunks from the subscription, filters out data-* subscription echo chunks to avoid double-rendering the user's own message, accumulates/flushed text, posts generated files, renders tool-call/tool-result/tool-call-approval/tripwire/error/abort chunks, and resets per-run rendering state (toolCalls, seedApprovalContext) on finish/error/abort. - Tool approval flow: resumed streams are processed via the cached thread subscription (not rendered directly). Approval-card metadata is seeded into pendingApprovalCards so existing cards are edited rather than duplicated when tool-result chunks arrive; approve/deny handlers now drain resumed streams so resumed runs complete and render. - Event context helper: buildEventContext() consolidates ChannelContext, attributes, and signalMetadata shapes used across handlers, LLM inputs, and consumers. - Public API: AgentChannels.close() unsubscribes all cached thread subscriptions and clears pending approval state for tests and graceful shutdown; tests added verifying close() behavior (cache drain, safe no-op, resilience to failing unsubscribe handlers). - Media handling: introduces DEFAULT_INLINE_MEDIA_TYPES = ['image/png','image/jpeg','image/webp','application/pdf'], updates inline media/link emission and v5 mediaType on file parts, and falls back to text when media fetch fails. - Slack provider and payload handling: SlackProvider preserves existing AgentChannels.channelConfig by merging the Slack adapter instead of replacing it, and only parses request bodies as JSON when Content-Type is application/json (fixes url_verification and form-urlencoded interactive payload handling). - Runtime resume fix: subscribeToThread()/thread-stream-runtime now removes completed/aborted runIds from the seen set so the same runId can be re-enqueued on resume and delivered to subscribers. - Dependency & docs: bumped chat dependency to ^4.29.0; updated reference docs to reflect signal-based routing; added changesets documenting behavior and fixes. ## Tests & Validation - All 84 channel tests pass (including three new close() tests). - Typecheck clean. - Manual Slack smoke tests (back-to-back DMs, channel mention, tool-approval round-trip) validated the shared-subscription rendering behavior. ## Notable Fixes - Avoids concurrent agent runs and duplicated/interleaved output by serializing delivery per Mastra thread. - Fixes Slack interactive payload handling by conditional JSON parsing. - Ensures resumed runs are fanned out to subscribers and drained on approval/denial so runs complete and render correctly. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16517?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: CalebBarnes <CalebBarnes@users.noreply.github.com> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
…astra-ai#16839) ## Description Fixes readability and alignment issues in the quiet mode task list. The compact horizontal layout made text hard to scan because it used `dim` (the lowest-contrast theme color) for nearly everything. Also replaced `stripAnsi().length` with pi-tui's `visibleWidth()` for accurate terminal column measurement — other TUI components already use this function. **Contrast changes:** - Counter prefix (`1/5`): `dim` → `muted` — key progress info should be readable at a glance - Pending item text: `dim` → `muted` — items need to be scannable in the dense horizontal layout - Completed items: `success` (green) → `dim` with strikethrough — done tasks should fade, not compete with in-progress items for attention Both `muted` and `dim` are WCAG contrast-adapted through the theme system (`ensureContrast()` at `TUI_MIN_CONTRAST = 5.5:1`), but `muted` provides noticeably better readability in a packed layout. **Alignment fix:** - Replaced `stripAnsi(str).length` with `visibleWidth(str)` from `@mariozechner/pi-tui` for width calculations in `formatQuietTaskLines`. `stripAnsi().length` counts JS characters, which can diverge from terminal display columns for Unicode icons (✓, ▶, ○). Other TUI components (status-line, overlay, plan-approval) already use `visibleWidth` for this reason. ## Related issue(s) Reported by Daniel in [Slack thread](https://kepler-bej6556.slack.com/archives/C0ACHFXNK7T/p1779290810208319?thread_ts=1779290810.208319&cid=C0ACHFXNK7T): quiet mode task list has contrast and alignment issues. ## Type of change - [x] Bug fix (non-breaking change that fixes an issue) ## Checklist - [x] I have linked the related issue(s) in the description above - [x] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works - [x] I have addressed all Coderabbit comments on this PR Link to Devin session: https://app.devin.ai/sessions/89b2b43bb1c5487db71680ae20307033 Requested by: @TylerBarnes <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Makes the quiet-mode UI easier to read and stops icons/Unicode from breaking alignment: counters and pending tasks are more visible, completed tasks are de-emphasized, and line-wrapping measures the terminal-visible width so glyphs don't misalign. ## Changes ### Bug Fix - Fixes readability and horizontal alignment in quiet-mode task lists and compact quiet tool displays. ### Contrast & Visual Changes - Counter prefix (e.g., `1/5`) changed from `dim` → `muted`. - Pending item text changed from `dim` → `muted`. - Completed items changed from green (`success`) → `dim` with strikethrough to de-emphasize. - Compact tool argument background adjusted from `#0f0f0f` → `#141414`. - Compact quiet rail/circle glyphs color selection now normalizes via a new contrast helper so glyphs remain visible on near-black and brighter terminal backgrounds. All muted/dim choices remain contrast-adapted by the theme (ensureContrast at TUI_MIN_CONTRAST = 5.5:1); new utilities provide special handling for near-black terminal backgrounds. ### Alignment & Measurement - Replace stripAnsi(str).length with visibleWidth(str) (from `@mariozechner/pi-tui`) in formatQuietTaskLines so terminal-visible column widths account for Unicode icons (✓, ▶, ○), preventing misalignment and incorrect wrapping. ### Theme & Utilities - Add exported helpers: - ensureContrastUnlessNearBlack(fgHex: string, minRatio = TUI_MIN_CONTRAST): string - ensureTerminalGlyphContrast(fgHex: string, minRatio = TUI_MIN_CONTRAST): string These adapt foreground contrast differently on near-black backgrounds vs. brighter backgrounds. ### Tests - Add/extend tests for: - ensureContrastUnlessNearBlack and ensureTerminalGlyphContrast behavior across near-black and brighter backgrounds. - Updated expected terminal color output for compact quiet tool badges and rail/glyph contrast. - Updated TUI component tests to match the new coloring and truncation/continuation behavior. ### Files Modified (high-level) - .changeset/large-olives-see.md — release notes - mastracode/src/tui/components/task-progress.ts — use visibleWidth; quiet-mode coloring & formatting updates - mastracode/src/tui/components/tool-execution-enhanced.ts — compact quiet styling refactor, rail/glyph color normalization, COMPACT_TOOL_ARGS_BG change - mastracode/src/tui/theme.ts — added near-black contrast helpers and related constants - mastracode/src/tui/__tests__/theme-contrast.test.ts — tests for new contrast helpers - mastracode/src/tui/components/__tests__/tool-execution-enhanced.test.ts — updated expected colors/outputs for compact quiet badges - Other TUI tests updated to reflect adjusted output/truncation/continuation behavior ## Type Non-breaking bug fix (mastracode package) <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16839?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: tyler <tylerdbarnes@gmail.com> Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
…stra-ai#16832) ## Description The Metrics page date picker only offered fixed relative presets (last 24h/3d/7d/14d/30d) with no way to select an arbitrary date range, unlike the Traces page. This swaps the plain dropdown for the shared `DateTimeRangePicker` so users can filter metrics by a custom start/end date and time, matching the Traces experience. ## Before <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/6f7146bf-5be8-4858-97e0-324e993d7008" /> ## After <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/47945c69-8da9-4b2a-87b7-ea8741001b09" /> - Replaced the `SelectFieldBlock` dropdown in `DateRangeSelector` with the shared `DateTimeRangePicker` (the same component the Traces page uses), exposing the `Custom range…` calendar - Added `toPickerPreset`/`fromPickerPreset` mappers to bridge the metrics preset values (`24h`, `3d`, …) and the picker's values (`last-24h`, `last-3d`, …) - Bridged the picker's per-field `onDateChange` to the provider's whole-range `setCustomRange`, with refs that guard the spurious change fired on non-custom preset switches and merge the two field updates (mirrors the Traces approach) - Wired `dateFrom`/`dateTo` URL params in the Metrics page: parse them into `customRange`, clear them when switching back to a relative preset, and pass `customRange` + `onCustomRangeChange` into `MetricsProvider` - The data layer already consumed `customRange`, so no query/aggregation changes were needed ## Related Issue(s) Fixes mastra-ai#16814 ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 The Metrics page date picker now lets you pick any exact start and end date/time ("Custom range…") instead of only fixed presets like "Last 24 hours." The chosen custom range is reflected in the URL so it can be shared/bookmarked and is cleared when you switch back to a relative preset. ## Changes ### Metrics Date Range Picker UI Replacement - Replaced the fixed-presets dropdown (`SelectFieldBlock` using `DATE_PRESETS`) in DateRangeSelector with the shared `DateTimeRangePicker`, exposing the "Custom range…" calendar. - Added bidirectional preset mappers (`toPickerPreset` / `fromPickerPreset`) to translate metrics preset values (`24h`, `3d`, `7d`, `14d`, `30d`, `custom`) ↔ picker presets (`last-24h`, `last-3d`, `last-7d`, `last-14d`, `last-30d`, `custom`). - Bridged the picker's per-field `onDateChange` to the provider's whole-range `setCustomRange` using refs (`presetRef`, `customRangeRef`) so field updates are ignored during non-custom preset switches and merged correctly for custom ranges (mirrors Traces behavior). ### Metrics Page URL Parameter Handling - Introduced DATE_FROM_PARAM / DATE_TO_PARAM and parse `dateFrom`/`dateTo` URL params into `customRange` when the selected preset is `custom`. - Added `onCustomRangeChange` to write/remove `dateFrom`/`dateTo` in the URL and to clear those params automatically when switching away from a relative preset. - Passed `customRange` and `onCustomRangeChange` into `MetricsProvider`. ### Tests & Release - Updated e2e tests to reflect the DateTimeRangePicker's button/menu UI (selectors changed from combobox/options to button/menuitem). - Added a changeset to release `@mastra/playground-ui` as a minor version and updated release notes documenting custom date range support. ## Notes - No data-layer query or aggregation changes were required; the data layer already consumes `customRange`. ## Fixes - Fixes issue `mastra-ai#16814` (adds the missing "Custom range" option to the Metrics page). <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16832?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Anurag Ojha <aojharaj2004@gmail.com> Co-authored-by: Damien Schneider <74979845+damien-schneider@users.noreply.github.com>
mastra-ai#16846) Co-authored-by: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>
## Description Adds post hog events to track when enterprise edition licenses are invoked and what features they're invoked for. ## Related issue(s) N/A ## Type of change - [x] Telemetry change ## Checklist - [ ] I have linked the related issue(s) in the description above - [ ] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/mastra-ai/mastra/pull/16660" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review"> </picture> </a> <!-- devin-review-badge-end --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 (Explain Like I'm 5) This PR makes the Enterprise edition quietly tell PostHog when an EE license is checked and when EE-only features (RBAC/FGA) are used — but it only sends hashed/anonymous identifiers so no raw license keys, emails, or user-agents are leaked, and telemetry can be turned off. ## Overview Adds PostHog-based, privacy-preserving EE telemetry to core that emits two event types: ee_license_check and ee_feature_used. Telemetry uses hashed license identifiers and a machine-level fallback distinctId, includes non-sensitive system/license metadata, respects MASTRA_TELEMETRY_DISABLED=1, and is implemented so telemetry failures never affect auth/authorization flows. ## Key Changes - Telemetry infra - New module: packages/core/src/telemetry/posthog.ts - EEEventName type, isEETelemetryEnabled(), hashTelemetryValue(), getEETelemetryFallbackDistinctId(), captureEEEvent(), resetEETelemetryForTests(). - Lazily initializes a singleton PostHog client (posthog-node), attaches system properties (os, node, machine_id, mastra_version), and swallows errors so telemetry never breaks runtime behavior. - License & feature tracking - packages/core/src/auth/ee/license.ts - Added SafeLicenseSummary and getSafeLicenseSummary() producing telemetry-safe licenseHash (truncated) and anonymousId, plus validity, features, tier, and dev-environment flag. - packages/core/src/auth/ee/capabilities.ts - buildCapabilities now invokes captureLicenseCheck to emit ee_license_check with safe license summary, capability flags, and client IP (x-forwarded-for / x-real-ip); emits ee_feature_used when RBAC access is resolved (role/permission counts, org membership id). Telemetry is try/catch-wrapped. - packages/core/src/auth/ee/fga-check.ts - requireFGA emits ee_feature_used on successful FGA checks with resource_type/id, permission, org membership id, and safe license fields; telemetry failures are ignored. - Tests - packages/core/src/telemetry/posthog.test.ts - Mocks posthog-node to verify enable/disable behavior, fallback distinctId/machine_id, and that capture errors are swallowed. - packages/core/src/auth/ee/__tests__/ee-telemetry.test.ts - Verifies ee_license_check (IP parsing, validity, no leakage of license/email/user-agent), ee_feature_used for RBAC and FGA (counts and org membership), and that FGA still succeeds if telemetry capture throws. - Dependency & changelog - packages/core/package.json: added dependency posthog-node@^5.30.6. - .changeset/easy-pumas-follow.md: documents EE telemetry behavior and the disable switch. ## Notes for reviewers / Outstanding items - Change type: telemetry (non-functional) but introduces a runtime dependency on posthog-node and a hard-coded PostHog host/key in the module. - Telemetry is enabled by default for EE and can be disabled with MASTRA_TELEMETRY_DISABLED=1; community users (no EE license) are unaffected. - Telemetry is implemented to avoid leaking raw secrets and to not affect authorization/auth flows; tests cover key behaviors. - Documentation: only the changeset was updated; no public docs or related-issue link added. Some automated reviewer (Coderabbit) comments remain unaddressed. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/mastra-ai/mastra/pull/16660?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
abhiaiyer91
pushed a commit
that referenced
this pull request
May 20, 2026
…ments (mastra-ai#16117) ## Description Tools that return AI SDK v5 `image-data` content blocks via `toModelOutput` were having their base64 payloads stringified into the observational-memory observer's text prompt, blowing past token limits and producing degenerate observer output. This change extracts media blocks out of tool-result outputs and passes them to the observer as real attachments — mirroring the existing handling for user-side `image` and `file` message parts. - Added `mapToolResultBlockToAttachment` to translate AI SDK v5 content blocks (`image-data`, `image-url`, `media`, `file-data`, `file-url`) into `ObserverAttachmentPart` form, building `data:<mediaType>;base64,<data>` URIs for inline blocks. - Added `extractToolResultAttachments` which walks `{ type: 'content', value: [...] }` tool outputs, hoists media blocks as attachments, and replaces each block in the residual with `{ type, placeholder: '[Image #N: ...]' }` so the JSON-stringified body stays small and shape-stable. - Wired the extractor into the `tool-invocation` result branch of `formatObserverMessage` so attachments flow through to `buildObserverHistoryMessage` alongside the existing image/file part path. - Non-content outputs (`text`, `json`, `error-text`, `error-json`, `execution-denied`) and unknown block types (`image-file-id`, `file-id`, `custom`) pass through unchanged. - Added three regression tests in `observational-memory.test.ts`: image-data block becomes a placeholder in `formatMessagesForObserver`, plain object tool results still serialize as JSON, and `buildObserverHistoryMessage` emits a real `{ type: 'image' }` attachment with the correct data URI and `mimeType`. ## Related Issue(s) Fixes mastra-ai#15883 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [ ] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Tools were embedding full images/files as huge text blobs, which made messages too large and broke prompts. This PR pulls those images/files out of the text and sends them as attachments, leaving small numbered placeholders in the text to keep order and context without the bloat. ## Overview Detects AI SDK v5 content blocks inside tool-result outputs (image-data, image-url, media, file-data, file-url), hoists recognized media/file blocks into ObserverAttachmentPart entries, and for inline binary blocks builds data:<mediaType>;base64,<data> URIs. The extractor replaces the original blocks in the residual content with compact numbered placeholder blocks (e.g., { type, placeholder: '[Image #1: image/png]' }) so the JSON-stringified body stays small and shape-stable. The extractor is integrated into the tool-invocation result branch of formatObserverMessage so attachments flow into buildObserverHistoryMessage alongside existing user-attached image/file parts. Non-content outputs (text, json, error-text, error-json, execution-denied) and unknown/unsupported block types (image-file-id, file-id, custom) pass through unchanged. ## Key changes - Added mapToolResultBlockToAttachment: translates content blocks into ObserverAttachmentPart (creates data: URIs for inline blocks). - Added extractToolResultAttachments: walks content outputs ({ type: 'content', value: [...] }), hoists media/file blocks into attachments, and replaces them with numbered placeholder blocks in the residual content. - Wired the extractor into formatObserverMessage/observer-agent so hoisted attachments are appended to message attachments and the textual "Tool Result …" parts contain placeholders instead of raw base64. - Ensures image/file numbering counter is shared between user-attached parts and tool-result attachments so placeholders are sequential and stable. ## Tests - Added regression tests in observational-memory.test.ts: - formatMessagesForObserver produces placeholders for image-data and ensures base64 does not appear in formatted text. - Plain-object tool results still serialize to JSON correctly. - buildObserverHistoryMessage emits { type: 'image' } attachments with correct data: URI and mimeType, and verifies shared numbering between user-attached and tool-result images. - Coverage includes image/file URL blocks, generic media blocks, and image-data without mediaType. ## Docs / Changeset - .changeset entry describing the fix to prevent token-limit failures by hoisting media/file blocks into attachments and inserting placeholders in text. ## Issue resolved Fixes mastra-ai#15883 — observational memory now delivers tool-produced image/file data as attachments with placeholder references in text, preventing token-limit overflows while preserving positional context. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Tyler Barnes <tylerdbarnes@gmail.com> Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
abhiaiyer91
pushed a commit
that referenced
this pull request
May 20, 2026
…mastra-ai#14237) This implements Phase 2 of the memory resource scoping, enforcing resourceId isolation across Postgres and LibSQL storage drivers. It references PR #1 which introduced the interface changes. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ELI5: The PR makes thread lookups respect a "resource" label so a thread from one tenant/resource can't be read by another. It updates thread-getting methods across storage drivers and adds tests to ensure the isolation works. * **What changed** * Enforce resourceId scoping for memory/thread retrieval across SQL drivers (Postgres, LibSQL) and all memory-backed storage adapters by extending getThreadById to accept an optional resourceId and return null when the stored thread’s resourceId does not match. * Updated the abstract MemoryStorage API (packages/core) and in-memory implementation to include the optional resourceId parameter. * Applied the same optional resourceId check in adapters for: Postgres, LibSQL, ClickHouse, Cloudflare (D1, DO, KV), Convex, DynamoDB, Lance, MongoDB, MSSQL, Redis, Upstash and related memory wrappers. * Updated packages/memory to forward resourceId in Memory.getThreadById and adjusted the wrapper signature accordingly. * **Tests** * Moved/added resourceId isolation tests into the shared threads test suite (stores/_test-utils/src/domains/memory/threads.ts) verifying: matching resource returns the thread, mismatched resource returns null, and omission of resourceId remains backward-compatible. * **Documentation / Release** * Added changeset (.changeset/memory-isolation-phase-2.md) documenting the change and bumping affected packages. * **Notes for reviewers** * Public API: MemoryStorage.getThreadById signature changed to accept optional resourceId — adapter implementations were updated accordingly. * Behaviour: When resourceId is provided, lookups are now resource-scoped and will return null for non-matching resourceIds; when omitted, existing behavior is preserved. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Sigmabrogz <bnb1000bnb@gmail.com> Co-authored-by: Sigmabrogz <sigmabrogz@gmail.com> Co-authored-by: Tyler Barnes <tylerdbarnes@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MastraAuthOktaconcatenates/v1/authorize(and/token,/keys,/logout) ontoOKTA_ISSUERverbatim. For a custom authorization server (https://{domain}/oauth2/default) that yields the right endpoint, but for an Okta org authorization server (https://{domain}) it produceshttps://{domain}/v1/authorize, which Okta 404s. The correct org-server endpoint ishttps://{domain}/oauth2/v1/authorize.Fix
Derive an internal
endpointBase—issuerverbatim when it already contains/oauth2/, otherwise${issuer}/oauth2— and use it for the authorize, token, keys, and logout URLs. JWTiss-claim validation still uses the rawissuer, so token validation stays correct on both server types. Trailing slashes on the issuer are normalized soOKTA_ISSUER=https://{domain}/no longer produces.../oauth2//v1/....OKTA_ISSUER=https://{domain}(org)https://{domain}/v1/authorize(404)https://{domain}/oauth2/v1/authorizeOKTA_ISSUER=https://{domain}/oauth2/default(custom)https://{domain}/oauth2/default/v1/authorizehttps://{domain}/oauth2/default/v1/authorize(unchanged)Both match what each Okta server type's discovery document advertises.
Test plan
iss-claim behavior inauth/okta/src/index.test.tspnpm --filter @mastra/auth-okta test— 35 passed🤖 Generated with Claude Code