Add Mesa as a workspace filesystem provider - #1
Draft
warrenbhw wants to merge 88 commits into
Draft
Conversation
warrenbhw
force-pushed
the
warrenbhw/mesa-filesystem-integration
branch
13 times, most recently
from
June 29, 2026 07:22
3898465 to
1c61cd3
Compare
…ructure and scale it in CI (mastra-ai#18514) ## Summary This PR does two things to the `packages/playground` Playwright E2E suite: it standardizes every spec on a single BDD structure (enforced by lint), and it speeds up the suite in CI by scaling out the shard matrix. ## 1. Standardize the E2E suite on a lint-enforced BDD structure The Playwright E2E suite is restructured to use the same BDD shape already used by the package's MSW Vitest tests, so both suites read the same way and the structure is enforced by lint instead of relying on convention. The shape, applied to all 53 e2e specs: - outer `test.describe` = the unit under test - inner `test.describe('when …')` = exactly one precondition - each `test` = exactly one observable outcome What's included: - **All 53 e2e specs restructured** into the BDD shape with no change to what they assert and no change to the number of tests. - **Lint enforcement**: a custom rule in `packages/playground/eslint.config.js` flags any bare `test`/`it` whose nearest enclosing `describe` title does not start with `when`. It handles interpolated `when` titles and ignores legitimate `test.skip` guards. The rule runs over `e2e/tests/**/*.spec.ts`, which were previously not lint-covered at all. - **Docs**: the BDD convention is now documented in `.claude/skills/e2e-tests-studio/SKILL.md` and `packages/playground/AGENTS.md`, so new E2E tests follow the same structure. - **Snapshot re-baselines**: three ARIA snapshots were regenerated 1:1 after the `describe` title renames changed their filenames; the regenerated breadcrumb snapshots reflect the app's current accessible name (`navigation "Breadcrumb"`), and the orphaned old files were removed. Verification: - Lint: 0 errors (pre-existing warnings only); the new BDD rule was verified firing on a deliberate flat probe and quiet on valid specs. - Full Playwright suite: **277 passed / 34 skipped / 0 failed**, including the re-baselined snapshot tests. ## 2. Scale the kitchen-sink E2E run in CI (shard matrix) The playground E2E run was split across only **3 shards**. Each shard already runs on its own runner with its own server and its own `e2e-test-storage.db`, so cross-shard parallelism is already isolated and safe — there just weren't enough shards. No changes to test isolation, the kitchen-sink server, or the storage model. - **Widened the shard matrix** in `.github/workflows/e2e-tests.yml` (`e2e-kitchen-sink`). The job name and `--shard` argument already interpolate `strategy.job-total`, so adding matrix entries was sufficient — no command edits. `fail-fast: false` is kept so every shard reports independently. - **Scoped the per-shard `Build` step** to a turbo filter of just the kitchen-sink runtime chain instead of a full `pnpm build`, shrinking the cache-restore surface so adding shards stays cheap. The filtered set resolves the full transitive graph and boots `mastra dev` cleanly (verified in CI — no webServer startup timeout). The full build still runs once in `prebuild` and warms the remote turbo cache. The final shard count was **tuned from measured CI wall-clock**, not guessed: | Config | Long pole (slowest shard) | CI cost (shard-minutes) | |---|---|---| | 3 shards (baseline) | 5m46s | ~17m | | **4 shards (settled)** | **5m25s** | ~19m | | 6 shards | 4m55s | ~23m | Going 3→6 only cut the long pole ~50s while adding ~6 shard-minutes of CI cost, because the bottleneck is no longer test volume — it's per-shard fixed overhead (deps, Playwright/Chromium install, cache restore, server boot) plus file-level shard imbalance. **4 shards sits at the knee of the curve**, capturing nearly all the achievable win at lower CI cost, so the matrix is settled at `[1, 2, 3, 4]`. All shards green, no retry-masked flakiness. Out of scope (follow-up): the remaining ~2-min spread between fastest and slowest shard comes from heavy specs (auth/RBAC, workflow-debug) clustering on one shard. Reducing the long pole further needs test-level balancing, not more shards. ## Notes No changeset: this is test/tooling/CI/docs only, with no shipped package behavior change. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR reorganizes the Playwright end-to-end tests so they read like clear “stories” (setup → when it happens → expected result). It also makes the biggest CI Playwright run faster by running fewer/building less work per shard, while keeping the same test checks. ## Summary - Standardized all `packages/playground` Playwright E2E specs (53 files) to a consistent BDD-style structure: - outer `test.describe` = feature/page under test - inner `test.describe('when …')` = one precondition - leaf `test(...)` = one observable outcome - assertions and test counts were preserved (structural/naming-only changes) - Added an ESLint rule (`e2e-bdd/test-needs-when-describe`) for `e2e/tests/**/*.spec.{js,jsx,ts,tsx}` to error when a bare `test()`/`it()` is not nested under a nearest `describe` whose title starts with `when` (with guidance for linting configuration in `eslint.config.js`). - Documented the convention and templates in: - `.claude/skills/e2e-tests-studio/SKILL.md` - `packages/playground/AGENTS.md` - Regenerated 3 ARIA snapshots whose filenames changed due to `describe` title updates. - CI performance improvements for the “kitchen-sink” Playwright run: - expanded sharding from 3 shards to 4 (`[1,2,3]` → `[1,2,3,4]`) - narrowed the per-shard build step to a turbo-filtered build chain (instead of a full build) ## Notable impact - No behavioral assertion changes—tests were reorganized and re-grouped to match the enforced BDD convention. - Playwright suite result: **277 passed, 34 skipped, 0 failed**. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (anthropic/claude-opus-4-8) <noreply@mastra.ai> Co-authored-by: Damien Schneider <74979845+damien-schneider@users.noreply.github.com>
warrenbhw
force-pushed
the
warrenbhw/mesa-filesystem-integration
branch
3 times, most recently
from
June 29, 2026 07:58
68f17f8 to
2c6aa96
Compare
## Description Fixes a recurring lint formatting issue in `session.ts` that causes CI failures across multiple PRs. ## 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: This change is a tiny cleanup in `session.ts` that makes one boolean check easier for the linter to قبول, so CI stops failing on formatting. It doesn’t change how tool-call resuming works. ### What changed - Simplified the `isInteractive` assignment in `Session.resumeToolCall` to a single-line boolean expression. - Kept the existing behavior for detecting interactive built-in suspended tools (`ask_user` / `request_access`) unchanged. ### Impact - No public API changes. - Non-breaking bug fix. - Helps prevent recurring lint formatting failures in CI. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
warrenbhw
force-pushed
the
warrenbhw/mesa-filesystem-integration
branch
2 times, most recently
from
June 29, 2026 08:02
34a9874 to
80f5e70
Compare
warrenbhw
force-pushed
the
warrenbhw/mesa-filesystem-integration
branch
from
June 29, 2026 08:06
80f5e70 to
b25f445
Compare
…astra-ai#18569) ## Description Inline skills created via `createSkill()` were not displayed in the Mastra Dev Portal because the server only queried workspace-level skills. This fix updates the server handlers to use the Agent's public API (`agent.listSkills()` and `agent.getSkill()`) which merges both inline and workspace skills. - Replace `agent.getWorkspace().skills.list()` with `agent.listSkills()` in `getSerializedSkillsFromAgent()` - Replace `workspace.skills.get()` with `agent.getSkill()` in `GET_AGENT_SKILL_ROUTE` handler - Remove now-unnecessary workspace null checks since the Agent API handles this internally ## Before <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/65f1bfed-26e6-42a8-b453-cd6371416031" /> ## After <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/32c155d3-1676-4f42-84bc-24d6e093e726" /> ## Related Issue(s) Fixes mastra-ai#18568 ## 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) - [ ] 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 change makes sure skills added directly to an agent show up in the Dev Portal too, not just skills that come from the workspace. It does this by asking the agent itself for its skills, so the portal now sees everything the agent can use. ### Summary of changes - Updated server skill serialization to use `agent.listSkills()` so both inline and workspace skills are included. - Updated the agent skill lookup route to use `agent.getSkill(identifier, { requestContext })`. - Removed now-unnecessary workspace null/config checks from the skill handler logic. - Bumped `@mastra/server` in the changeset and clarified the Dev Portal visibility fix. <!-- 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 This change fixes some broken links in the docs by sending old Harness page URLs to their new home. It also adds a few more redirects so people who use the old pages still end up in the right place. ## Summary - Updated `docs/vercel.json` redirect rules for `/docs/harness/*` paths. - Moved the existing redirects into a new block later in the array. - Kept the redirects permanent and expanded coverage to include: - `/docs/harness/overview` - `/docs/harness/session` - `/docs/harness/threads-and-state` - `/docs/harness/modes` - `/docs/harness/subagents` - `/docs/harness/tool-approvals` - All of these now point to the corresponding `/docs/agent-controller/*` pages. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…tra-ai#18598) ## Description Studio's Metrics tab refused to render for `PostgresStoreVNext` users, showing "Metrics are not available with your current storage" even though the backend fully implements metric queries and returns real data. The UI gate used a hardcoded allowlist of observability storage types that was never updated when Postgres v-next observability landed in PR mastra-ai#16760. - Added `ObservabilityStoragePostgresVNext` to the `ANALYTICS_OBSERVABILITY_TYPES` set in the metrics page - Updated the empty-state description to list Postgres v-next as a supported backend - Corrected `overview.mdx` and `automatic-metrics.mdx` docs that incorrectly blanket-excluded PostgreSQL from metrics support ## Related Issue(s) Fixes mastra-ai#18593 ## 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) - [x] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [x] 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 Before this, the Studio “Metrics” tab hid itself for Postgres v-next users even though the backend can fetch metrics. This PR adds Postgres v-next to the allowlist and updates the messages/docs so the UI and documentation agree with what actually works. ## Summary - Updated the Studio Metrics UI gating logic to include `ObservabilityStoragePostgresVNext`, so the Metrics tab renders for Postgres v-next observability stores. - Revised the Metrics empty-state and guidance to explicitly list Postgres v-next as supported (and clarify when/why time-range filters matter). - Updated observability metrics documentation (`overview.mdx`, `automatic-metrics.mdx`) to remove the blanket exclusion of PostgreSQL and reflect Postgres v-next support. - Added a changeset noting that the Studio Metrics tab now works for `PostgresStoreVNext`. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com>
… values (mastra-ai#18529) ## Description MCP stdio server `env` values were passed through verbatim, while HTTP server headers already resolved `${VAR}` references from the environment (mastra-ai#18240). This applies the same expansion to stdio `env`, so secrets can be referenced from the host environment instead of being hardcoded in `mcp.json`. The behavior now matches how Claude Code resolves values in `.mcp.json`, which the config loader already documents as its goal. `expandEnvValues` mirrors the existing `expandHeaderEnvVars` helper and reuses `expandEnvVars`, so `${VAR}`, `${VAR:-default}`, and bare `$VAR` forms all resolve consistently. ## Related issue(s) Fixes mastra-ai#18528 ## 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 - [x] 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This change lets MCP stdio servers use secrets from your computer’s environment variables instead of typing them into config files. So if `mcp.json` says `"${GITHUB_TOKEN}"`, it now turns into the real token before the server starts, just like HTTP config already did. ## Summary - Expanded `${VAR}`, `${VAR:-default}`, and `$VAR` references in stdio server `env` values using the host environment. - Reused the existing environment expansion logic so stdio behavior now matches HTTP header handling. - Added a test covering stdio `env` expansion and env cleanup/restoration. - Added a changelog note describing the new stdio env interpolation behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
) ## Description `chatRoute` (and the underlying `handleChatStream`) from `@mastra/ai-sdk` ignored any agent config edited through the Agent Editor. It resolved the agent with a plain `mastra.getAgentById(agentId)` and ran the bare, code-defined agent — so anything a user changed in the editor (instructions, tools, model) was silently dropped on this endpoint, while Studio served the edited config correctly. This is most visible when the instructions live entirely in the editor's stored config (for example `MastraEditor({ source: 'code' })`, where the instructions are removed from the `Agent({...})` definition and kept in a per-agent JSON file). In that setup the endpoint sent **empty** instructions to the model and the agent could not answer, even though the exact same agent worked in Studio. ### Root cause There are two paths that turn an agent ID into a runnable agent, and only one of them applied the editor's stored config: - **Studio** uses the built-in handler `getAgentFromMastra` (`@mastra/server`), which, after finding the code agent, calls `editor.agent.applyStoredOverrides(agent, { status: 'published' }, requestContext)`. The stored edits are layered on top of the code agent. - **`chatRoute` / `handleChatStream`** (`@mastra/ai-sdk`) skipped that step entirely unless the caller explicitly passed a `?versionId=` / `?status=` query param. A normal request fell through to the bare code agent. So the instructions were never missing — they were sitting in the editor's stored config, and `handleChatStream` simply never looked there. ### The fix `handleChatStream` now resolves the agent the same way Studio does. When an editor is configured, it routes the agent through `applyStoredOverrides`, defaulting to the **published** version and threading `requestContext`. An explicit `agentVersion` (from query params or route options) still takes precedence. ```ts // before const agentObj = agentVersion ? await mastra.getAgentById(agentId, agentVersion) : mastra.getAgentById(agentId); // bare code agent — editor edits ignored // after const baseAgent = mastra.getAgentById(agentId); const editorAgent = mastra.getEditor?.()?.agent; if (editorAgent) { agentObj = await editorAgent.applyStoredOverrides( baseAgent, agentVersion ?? { status: 'published' }, // explicit version wins, else published requestContext, ); } ``` When no editor is configured, behavior is unchanged: `applyStoredOverrides` is never called, and the code agent runs exactly as before. When an editor is configured but the agent has no stored config, `applyStoredOverrides` returns the code agent untouched — so non-editor and not-yet-edited agents are unaffected. ### Behavior, before vs after | Path | Before | After | | --- | --- | --- | | Studio | edited instructions ✅ | edited instructions ✅ | | `chatRoute` endpoint | bare code agent (empty/stale instructions) ❌ | edited instructions ✅ | ## Related issue(s) Fixes mastra-ai#18574 ## 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 - [x] 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Before this change, the `/chat` endpoint sometimes ran the “original” agent code instead of the edited agent settings you saved in the Editor. Now it pulls the saved overrides (like instructions and tools) and uses them when streaming chat, so the agent behaves the way Studio shows. ## Summary - Updated `@mastra/ai-sdk` `chatRoute` / `handleChatStream` to resolve the agent through `editor.agent.applyStoredOverrides` when an `@mastra/editor` is configured. - Defaulted stored-override resolution to the published agent version, while honoring an explicitly provided `agentVersion` to take precedence. - Threaded `requestContext` into `applyStoredOverrides` so override resolution matches Studio behavior. - Preserved the prior behavior when no editor is configured or when the editor has no stored config. - Added regression tests covering stored override resolution (including published default), explicit `agentVersion`, `requestContext` forwarding, and the no-editor/no-config fallbacks. - Added a changeset to patch `@mastra/ai-sdk` with the fix. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Anurag Ojha <aojharaj2004@gmail.com>
…wName omitted (mastra-ai#18586) ## What `WorkflowsInMemory.getWorkflowRunById` returns `null` when `workflowName` is omitted, even though a run with the given `runId` exists. `workflowName` is optional in the storage contract (`base.ts`: `getWorkflowRunById(args: { runId: string; workflowName?: string })`), and the persistent adapters honor that. The pg and libsql adapters only add the `workflow_name` condition `if (workflowName)` and otherwise match by `run_id` alone. The in-memory store instead always ran: ```ts const runs = Array.from(this.db.workflows.values()).filter(r => r.run_id === runId); let run = runs.find(r => r.workflow_name === workflowName); ``` When `workflowName` is `undefined`, `r.workflow_name === undefined` never matches a stored run (runs always carry a concrete name), so the method returns `null`. This makes the in-memory store behave differently from every persistent adapter for a contract-supported call. ## Change Match by `runId`, only filter by `workflowName` when it is provided, and return the most recent run (`createdAt DESC`) to match the pg/libsql behavior (`ORDER BY createdAt DESC LIMIT 1`). ## Tests Added unit tests covering the omitted-name case, the provided-name case (correct run and a wrong name returning null), and an unknown `runId`. I confirmed the new omitted-name test fails on the current code and passes after the fix. The wider storage suite and `workflows/state-reader` tests pass. Two unrelated suites in `packages/core/src/storage` (`filesystem.test.ts` and `bundle.test.ts`) fail on a clean checkout as well, due to a Windows temp-dir lock and a build-dependent skip, so they are not from this change. Closes mastra-ai#18585 --- cc @taofeeq-deru who owns most of this store. Small fix, happy to drop the createdAt ordering if you would rather keep the in-memory lookup minimal. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This change fixes a lookup bug in the in-memory workflow store. If you ask for a run by its ID and don’t give a workflow name, it now finds the right run instead of saying “not found,” just like the other storage backends. ### Summary - Fixed `WorkflowsInMemory.getWorkflowRunById` so `workflowName` is optional as the storage contract expects. - When `workflowName` is omitted, the lookup now matches by `runId` alone. - When `workflowName` is provided, it still filters by both `runId` and `workflowName`. - If multiple runs share the same `runId`, the most recent matching run is returned. - Added tests covering: - omitted `workflowName` - provided `workflowName` - wrong `workflowName` - unknown `runId` - Added a changeset documenting the behavior fix. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…mastra-ai#18582) ## What The Zod v4 date handler in `@mastra/schema-compat` produces inverted descriptions for `z.date().min()` and `z.date().max()`. The text attached to the schema, which is sent to the model, states the opposite and impossible bound. In Zod v4 a date bound is stored as a comparison check: - `z.date().min(d)` becomes a `greater_than` check with value `d`, so the date must be newer than `d`. - `z.date().max(d)` becomes a `less_than` check with value `d`, so the date must be older than `d`. `defaultZodDateHandler` in `schema-compatibility-v4.ts` mapped these the wrong way around: the `less_than` branch emitted "newer than" and the `greater_than` branch emitted "older than". The v3 handler in `schema-compatibility-v3.ts` maps them correctly, so the v4 port had the two branches swapped. For `z.date().min(new Date('2020-01-01')).max(new Date('2030-01-01'))`: - Before: `Date must be older than 2020-01-01T00:00:00.000Z (ISO), Date must be newer than 2030-01-01T00:00:00.000Z (ISO)` - After: `Date must be newer than 2020-01-01T00:00:00.000Z (ISO), Date must be older than 2030-01-01T00:00:00.000Z (ISO)` ## Change Swap the two messages in the v4 `defaultZodDateHandler` so they match Zod semantics and the existing v3 handler, and rename the local variables to match their actual bound. ## Tests Added unit tests for the lower bound, the upper bound, and the combined case, asserting both the correct phrasing and the absence of the inverted phrasing. The Zod v4 check kinds were verified at runtime (`min` yields `greater_than`, `max` yields `less_than`). All new tests pass, the full `@mastra/schema-compat` suite passes (28 files), and typecheck and lint are clean. Closes mastra-ai#18581 --- cc @TylerBarnes and @wardpeet who have worked on this file. Small fix, happy to adjust the wording if you prefer different phrasing. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This update fixes date messages so they say the right thing. If a date has a minimum, it now says it must be **newer** than that date; if it has a maximum, it now says it must be **older** than that date. ### What changed - Fixed `defaultZodDateHandler` in `schema-compatibility-v4.ts` so Zod v4 date checks use the correct wording: - `.min()` → “Date must be newer than …” - `.max()` → “Date must be older than …” - Kept the existing `Date format is date-time` text in generated descriptions. - Renamed local variables/comments to match the real lower/upper bound meaning. - Added tests covering: - lower-bound-only dates - upper-bound-only dates - combined `min` + `max` dates - correct phrasing and no inverted wording - Added a changeset documenting the patch fix for `@mastra/schema-compat`. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
… vector domains (mastra-ai#18393) Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> Signed-off-by: Casey Clements <casey.clements@mongodb.com>
…tra-ai#18674) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Ehindero Israel <ehindero2022@gmail.com>
Co-authored-by: Abhi Aiyer <abhi@mastra.ai>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…-ai#18556) ## Summary - Add a metadata-only MessageList update path keyed by toolCallId. - Use that path from background task onExecution hooks so lifecycle metadata does not rewrite the model-visible tool invocation state. - Cover the metadata-only behavior and durable background task hook with focused tests. Fixes mastra-ai#18551 ## Tests - pnpm build:core - pnpm --filter ./packages/core test src/agent/message-list/tests/update-tool-invocation.test.ts - pnpm --filter ./packages/core test src/agent/durable/workflows/steps/tool-call-bg.test.ts - pnpm --filter ./packages/core check <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 When a background tool starts, the agent stores a “task started” acknowledgement that the model should keep seeing. This PR saves the background task bookkeeping (task id + timestamps) in message metadata instead of overwriting the tool invocation itself, so the model-visible tool result/ack doesn’t get lost. ## Summary - Added `MessageList.updateMessageMetadataByToolCallId(toolCallId, metadata)` to update only `content.metadata.backgroundTasks` on the latest matching assistant `tool-invocation` (keyed by `toolCallId`), merging tasks by `toolCallId` without changing the tool invocation result/ack. - Added `mergeBackgroundTasks(existing, incoming)` and reused it from `updateToolInvocation(...)` so background-task metadata updates deep-merge/preserve existing per-task fields instead of overwriting them. - Updated background-task `onExecution` hooks: - Durable tool-call background workflow now records `startedAt`/`suspendedAt`/`taskId` via `updateMessageMetadataByToolCallId` and avoids downgrading/updating the tool invocation state. - Loop/tool-call background workflow similarly uses the metadata-only update keyed by `toolCallId`. - Expanded tests to cover: - Metadata-only updates preserving the existing `tool-invocation` object while updating only the targeted background task (and keeping unrelated tasks intact). - The durable `onExecution` path calling the metadata-only method (and not `updateToolInvocation` in that scenario). - `updateToolInvocation` deep-merging background-task metadata when transitioning to `result`. - Updated the `@mastra/core` changeset with a patch release documenting the fix. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ehindero Israel <ehindero2022@gmail.com> Co-authored-by: Taofeeq Oluderu <oluderutaofeeq@gmail.com> Co-authored-by: Ehindero Israel <ehindero@Ehinderos-MacBook-Pro.local> Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
…astra-ai#18695) Co-authored-by: Mastra Code (anthropic/claude-opus-4-8) <noreply@mastra.ai>
Co-authored-by: Mastra Code (anthropic/claude-opus-4-8) Co-authored-by: Mastra Code (anthropic/claude-opus-4-8) <noreply@mastra.ai>
## Summary
Adds a new `structuredOutput.jsonPromptInjection: 'inline'` mode.
Before this PR, JSON prompt injection put the structured-output schema
instructions in the system prompt (`true` / `'system'`). That works, but
it changes the system prompt for each schema and can defeat provider
prompt caching.
This PR adds an inline mode that appends the JSON instructions to the
latest user message instead, keeping the leading system prompt stable
and more cache-friendly.
```ts
await agent.generate('Extract the task details', {
structuredOutput: {
schema: taskSchema,
jsonPromptInjection: 'inline',
},
});
```
Behavior by mode:
```ts
jsonPromptInjection: true // inject into system prompt
jsonPromptInjection: 'system' // inject into system prompt
jsonPromptInjection: 'inline' // inject into latest user message
```
If there is no user message, inline mode adds a user message containing
the JSON instructions. Native `responseFormat` is still skipped whenever
prompt injection is enabled.
The structured-output fallback helpers preserve explicit `'inline'` /
`'system'` settings when retrying, instead of coercing every retry to
`true`.
## Test plan
- Stack rebase verified linear against mastra-ai#18651
- Covered by downstream memory/core checks in the stack
## Stack
- Previous: mastra-ai#18651
- Next: mastra-ai#18653
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This change lets the app add JSON “instructions” in a new “inline” way,
by attaching them to the user’s message instead of always putting them
in the system message. That helps keep the system prompt stable, which
can work better with providers that cache prompts.
## Summary
- Added support for `structuredOutput.jsonPromptInjection: 'inline'`
alongside `true` and `'system'`.
- Updated structured output handling so:
- `true` / `'system'` inject JSON instructions into the system prompt
- `'inline'` appends them to the latest user message
- if there is no user message, inline mode creates one
- Kept native `responseFormat` disabled whenever prompt injection is
enabled.
- Preserved explicit `'inline'` and `'system'` settings during JSON
fallback retries.
- Added the new runtime feature flag `json-prompt-injection:inline`.
- Expanded tests to cover inline injection, system injection,
missing-user-message behavior, and feature flag exposure.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary
Adds the observational memory extractor pipeline.
Extractors let OM capture structured values alongside observations,
persist selected values into thread metadata, and carry extraction
failures through the OM lifecycle. Extractor instructions and schemas
can be static or resolved from runtime context, so extraction can adapt
to the active agent and thread.
```ts
observationalMemory: {
enabled: true,
observation: {
extract: [
new Extractor({
slug: 'priority',
name: 'Priority',
schema: z.enum(['low', 'medium', 'high']),
instructions: 'Extract the user priority when it changes.',
}),
],
},
}
```
## Test plan
- `pnpm --filter ./packages/memory test:unit -- --run
src/processors/observational-memory/__tests__/extractor.test.ts
src/processors/observational-memory/__tests__/observational-memory-api.test.ts
--reporter=dot --bail 1`
- `pnpm --filter ./packages/memory check`
- Stack rebase verified linear against mastra-ai#18652
## Stack
- Previous: mastra-ai#18652
- Next: mastra-ai#18654
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
ELI5: This PR makes “observational memory” not only remember what
happened, but also automatically pull out specific structured facts
(like a user’s priority), save them on the thread, and reuse them later.
It also adds an `Extractor` API so you can define how those facts are
detected, validated, and what happens when extraction fails.
### Summary
- Added a public `Extractor` API for Observational Memory with:
- **inline (XML/tag-based)** and **structured (Zod/schema-based)**
extraction modes
- slug validation, runtime-resolved/dynamic `instructions` and optional
`schema`
- per-extractor `onExtracted` hooks to normalize/transform values and
record failures safely.
- Extended Observational Memory configuration with extraction pipelines:
- `observationalMemory.observation.extract` and
`observationalMemory.reflection.extract`
- built-in extractors (current task, suggested response, thread title)
composed with user extractors.
- Implemented extraction end-to-end across observer/reflector:
- prompt generation includes extractor output sections and optional
“prior extracted values”
- parsing supports extracting values from model output while stripping
extractor sections
- structured extraction retries/fallback behavior is handled, and
extracted values are validated/merged.
- Persisted extracted values into thread observational memory metadata
under `threadOMMetadata.extracted`, including carry-forward of prior
extracted values into subsequent observer/reflector runs.
- Propagated extraction failures through the OM lifecycle (without
blocking successful extractions):
- added `extractionFailures` alongside `extractedValues` in OM end
markers and marker/telemetry payloads.
- Updated exports/types and documentation:
- new/extended types for `extractedValues` and `extractionFailures`
across OM configs, runners, and storage
- added Observational Memory docs sections for “Extractors” plus an
“Extractor API” reference.
- Added tests covering extractor logic and Observational Memory
persistence across:
- extractor unit behavior (inline/structured parsing, retries, hooks,
prompt composition)
- observational-memory API behavior (observe/reflect/buffer) and thread
metadata persistence
- marker schema changes and additional observational-memory lifecycle
assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
Adds the first Mastra Code plugin system so users can install trusted
local or GitHub plugins and expose their tools inside the TUI.
Plugins can be a local path, or installed via a github url. When
installing from github it will clone it to the installed scope (project
or global) and MC will then periodically check if it needs to pull new
commits down.
For local plugins, it hot reloads tool changes, allowing MC to work on
its own tools via a plugin. It can modify the tool, call it, modify, etc
in a loop until it works properly.
```ts
import { defineMastraCodePlugin, createTool, z } from 'mastracode/plugin';
export default defineMastraCodePlugin({
id: 'example.plugin',
name: 'Example Plugin',
tools: {
example_tool: {
tool: createTool({
id: 'example_tool',
description: 'Run an example plugin tool',
inputSchema: z.object({ message: z.string() }),
execute: async context => ({ message: context.message }),
}),
},
},
});
```
Plugins can define tools, optional config, render hints, bundled slash
commands and skills, and plugin instructions. The `/plugins` UI handles
install, scaffold, details, config, enable/disable, and local/GitHub
source management. Local plugin edits reload at execution time, and
GitHub checkouts poll for updates while preserving local changes on
backup branches before resetting.
This also adds project-level plugin blocking, progress streaming for
plugin tools, subagent-style rendering for plugin tools that ask for it,
and a README note that plugins should only be installed from trusted
sources.
Smoke tested with Alexandria: the expert tool executes, config persists,
and bundled command/skill loading was tested earlier. Focused unit
tests, typecheck, and `pnpm build:mastracode` pass.
example plugin:
https://github.com/mastra-ai/alexandria/blob/main/.mastracode/plugins/sources/local/alexandria/src/index.ts#L101
<img width="675" height="103" alt="Screenshot 2026-06-29 at 5 07 24 PM"
src="https://github.com/user-attachments/assets/74db5628-e546-421b-9916-f68a9eed281d"
/>
<img width="890" height="328" alt="Screenshot 2026-06-29 at 5 07 39 PM"
src="https://github.com/user-attachments/assets/9b3c6add-1d98-4583-8e74-0a0f9fdbe99d"
/>
<img width="721" height="336" alt="Screenshot 2026-06-29 at 5 07 34 PM"
src="https://github.com/user-attachments/assets/f2d3e0be-c9b8-41ed-9208-56ff82f380ed"
/>
<img width="564" height="506" alt="Screenshot 2026-06-29 at 5 07 44 PM"
src="https://github.com/user-attachments/assets/6f082267-52c5-43a0-98af-3b3e06d4f582"
/>
<img width="2530" height="1156" alt="image (34)"
src="https://github.com/user-attachments/assets/e964bf8c-dbd3-4ead-b25e-3ea848ac93bf"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This PR adds a way for Mastra Code to load “trusted plugin” code so it
can learn new tools and commands. You can install plugins from your
computer or GitHub, manage them in the terminal UI, and see their tool
progress update live—plus reload plugins automatically when local code
changes or GitHub has updates.
## Summary
- Introduces the first Mastra Code plugin system:
- Public plugin API/types (`defineMastraCodePlugin`) and
`writeToolProgress` support
- `.mastracode-plugin.json` manifest handling
- Local + GitHub install, local discovery, scoped plugin registries
(load/merge/save), and a full plugin loader pipeline
- A `PluginManager` that tracks active plugins, supports reloads, and
handles local hot-reload + GitHub polling/update with backup/dirtiness
safety
- Project-level plugin blocking via `disabledPlugins`
- Wires plugins into the app runtime so plugin contributions work
everywhere:
- Merges plugin tool names into mode allowlists and dynamically builds
toolsets from loaded plugin tools
- Appends plugin-provided instructions into generated agent prompts
- Exposes plugin-provided assets via TUI/session state
(skills/commands/instructions), and treats plugin command dirs as extra
high-priority slash-command sources
- Adds `/plugins` TUI management with end-to-end flows:
- Install new plugins, scaffold plugin projects, view details, configure
plugin config values (including model selection + API key prompting),
enable/disable, uninstall
- Install-source management (local path vs GitHub URL) with
trust-confirmation guidance
- Includes block/disabled handling in the UI and behavior
(hidden/conflicted/blocked states)
- Improves plugin tool UX in chat/TUI:
- Streams plugin tool progress from core → TUI using
`data-mastracode-tool-progress`, emitting tool updates and rendering
progress output
- Adds “subagent-style” rendering for tools that request it, including
static subagent component handling and replay for previously stored tool
calls
- Supports local hot reloading and GitHub polling/update scenarios
- Tests + release notes:
- Adds unit tests for plugin loader/manager/registry/scaffold, plugin
instruction generation, tool-progress streaming, and tool rendering
precedence
- Adds TUI unit tests for `/plugins`
- Adds E2E fixtures covering bundled commands/skills, tool streaming,
local hot reload, GitHub poll updates, blocking/config behavior, and
scaffold/install/execute flows
- Updates docs and adds a changeset publishing “Mastra Code” plugin
support.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
Adds lightweight timing feedback to the Mastra Code TUI so it is easier to tell how long the agent has been working and how long it has been idle. Added e2e test and also smoke tested manually in the TUI: active timing, completed timing, and delayed idle display all looked good. <img width="343" height="129" alt="Screenshot 2026-06-29 at 10 27 52 AM" src="https://github.com/user-attachments/assets/adb2118f-37f2-468f-8186-9995ff853366" /> <img width="410" height="125" alt="Screenshot 2026-06-29 at 10 27 56 AM" src="https://github.com/user-attachments/assets/837dded7-9437-423b-8689-1dd12ea62ede" /> <img width="353" height="118" alt="Screenshot 2026-06-29 at 10 28 03 AM" src="https://github.com/user-attachments/assets/efd570c1-c37c-4bfd-acbc-daed76e781f7" /> <img width="449" height="205" alt="Screenshot 2026-06-29 at 10 28 45 AM" src="https://github.com/user-attachments/assets/5feb216d-dea7-4db3-820f-5f2ba311af7d" /> <img width="397" height="125" alt="Screenshot 2026-06-29 at 11 23 58 AM" src="https://github.com/user-attachments/assets/e3f46809-bdcd-4e1f-ac9d-013115221659" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR adds small “how long” timers to the Mastra Code terminal UI. You’ll see how long the agent has been working, how long the last run took when it finishes, and how long it’s been waiting/idle. ## Summary - **Status line timing for agent runs** - Shows **active elapsed time** while the agent is running (with “stale”/delayed styling when the stream hasn’t updated recently). - Shows **completed duration** with a **✓** for success and **×** for errors (and no success icon for intentional/“aborted” outcomes). - **Idle display driven by the last completed run** - Idle text now derives from **`lastAgentRunEndedAt`** (and minimum thresholds), rendering **“X idle”** after sufficient idle time. - **Shared timing formatting utilities** - Added `formatStatusDuration(ms)` plus new idle formatting helpers to consistently render durations like **`1m1s`**, **`1m`**, and **`1m idle`**. - **State/timer wiring updates in the TUI** - Added/used timing fields (`agentRunStartedAt`, `agentRunLastStreamPartAt`, `lastAgentRunDurationMs`, `lastAgentRunEndedAt`, `lastAgentRunEndReason`) and ensured the status line is re-rendered at the right event boundaries. - Replaced the prior idle-counter ticker with a unified **status timing timer** that updates both active and idle timing and pauses/resumes appropriately around message sending. - **E2E/test support + scenario** - Added an E2E hook (`onTuiCreated`) so scenarios can access the created TUI instance. - Added a new `work-idle-status` scenario + fixture to verify: - active timing appears, - completed timing appears, - idle timing transitions to **“1m idle”** after advancing simulated time. - **UI/behavior polish** - Adjusted agent-abort handling so intentional aborts don’t produce redundant “interrupted” error UI. ## Testing - Manual smoke testing in the TUI (active timing, completed timing, and delayed idle display). - Added/updated unit tests for status-line timing rendering, idle timing formatting/component API, stream-activity timing updates, and abort UI behavior. - Added an end-to-end TUI terminal scenario (`work-idle-status`) with a new fixture to validate the timing labels and idle transition. - Updated the `mastracode` changeset for a patch release describing the new status-area timing behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
## Summary
Adds a built-in WorkingMemoryExtractor and a simpler OM-managed working
memory setup.
With `manageWorkingMemory`, OM can extract working-memory updates from
observations and apply them after the turn. The sugar defaults working
memory to prompt-cache-friendly state signals and disables direct agent
tool management unless the user opts back in.
```ts
new Memory({
options: {
observationalMemory: {
enabled: true,
observation: {
manageWorkingMemory: true,
// extractors: [new WorkingMemoryExtractor()] <- added internally by manageWorkingMemory: true
},
},
workingMemory: {
enabled: true,
// these are configured internally by observation.manageWorkingMemory: true
// agentManaged: false, <- disables the agent managing working memory via tool calls and removes system instructions saying to do so
// useStateSignals: true,
},
},
});
```
Users who still want both paths can opt in explicitly:
```ts
workingMemory: {
enabled: true,
agentManaged: true
}
```
<img width="1013" height="889" alt="Screenshot 2026-06-29 at 3 54 07 PM"
src="https://github.com/user-attachments/assets/cccb97dd-ac5c-4898-b78a-f84f6cdd3bb0"
/>
<img width="1015" height="871" alt="Screenshot 2026-06-29 at 3 25 57 PM"
src="https://github.com/user-attachments/assets/7d06499f-45dc-443a-ac28-f1aa65f4ceb9"
/>
## Test plan
- `pnpm --filter ./packages/memory test:unit -- --run
src/processors/observational-memory/__tests__/extractor.test.ts
src/processors/observational-memory/__tests__/observational-memory-api.test.ts
--reporter=dot --bail 1`
- `pnpm --filter ./packages/memory check`
- Stack rebase verified linear against mastra-ai#18653
## Stack
- Previous: mastra-ai#18653
- Next: mastra-ai#18655
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5
This PR helps Observational Memory automatically “catch” what changed in
your app’s working memory as it watches the conversation, then apply
those updates for the agent after the turn. So the agent doesn’t have to
remember to call the working-memory tool every time—and the default
setup is tuned to stay friendly to prompt caching.
## Summary
- Added a built-in `WorkingMemoryExtractor` and re-exported it from the
Observational Memory module.
- Introduced `observationalMemory.observation.manageWorkingMemory` to
let Observational Memory extract working-memory updates and apply them
after the turn.
- Added `workingMemory.agentManaged` to control whether the main agent
still receives working-memory tool/instructions (`agentManaged` defaults
to `true` when not overridden).
- When OM manages working memory (`manageWorkingMemory: true` with
`workingMemory.enabled: true`), defaults change to:
- `workingMemory.agentManaged: false` (OM applies updates instead of the
agent)
- `workingMemory.useStateSignals: true` (prompt-cache-friendly)
- setting `workingMemory.agentManaged: true` preserves the “agent also
manages it” path.
- Updated memory behavior for tool exposure, system-message/tool
instruction wording, and merged thread config defaults to match the new
working-memory management rules.
- Extended unit/integration tests to verify extraction and persistence
for both markdown and JSON/schema-backed working memory modes, plus
`listTools()`/`getSystemMessage()`/merged-config behavior under the new
options.
- Updated documentation and a changeset to document the new
configuration flow and defaults (`manageWorkingMemory`, `agentManaged`,
and `useStateSignals`).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (crof/glm-5.2) <noreply@mastra.ai>
Add a new @mastra/mesa workspace filesystem package backed by Mesa repos. Document the provider, include focused unit and integration test coverage, and add the release changeset.
warrenbhw
force-pushed
the
warrenbhw/mesa-filesystem-integration
branch
from
June 30, 2026 21:41
909923d to
66036b2
Compare
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.
Adds a new
@mastra/mesaworkspace filesystem provider backed by Mesa repos. The provider mounts repos through the Mesa SDK, implements the Mastra workspace filesystem interface, and exposes Mesa-specific helpers likebash(),change,bookmark, and the mountedfilesystemfor advanced use.Also adds docs, README usage, focused unit/integration test coverage, a changeset, and the lockfile/package workspace updates needed for
@mesadev/sdk@0.38.0.Validated with:
corepack pnpm --filter ./workspaces/mesa test:unitcorepack pnpm --filter ./workspaces/mesa buildcorepack pnpm --filter ./workspaces/mesa lintcorepack pnpm --filter ./docs buildThe docs build still reports existing unrelated broken-anchor warnings in agent/evals docs.