Repository navigation
Add Mastra Code - #651
Open
jal-co wants to merge 3 commits into
Open
Add Mastra Code#651jal-co wants to merge 3 commits into
jal-co wants to merge 3 commits into
Conversation
3 tasks done
TylerBarnes
pushed a commit
to mastra-ai/mastra
that referenced
this pull request
Oct 4, 2026
## Description ACP clients can now sign in to Mastra Code without leaving the editor. `initialize` advertises browser sign-in for ChatGPT, Kimi For Coding, and xAI, which `authenticate` runs in-process. Clients that advertise terminal auth also get Claude and GitHub Copilot sign-in (`mastracode login --provider <id>`) and `mastracode-login` (`mastracode login`) for any other provider or an API key. The new command exits when sign-in finishes. `session/new` returns `auth_required` when no provider is configured, so clients surface those options. This is what the ACP registry requires to list Mastra Code (agentclientprotocol/registry#651). ```diff initialize - (no authMethods) + authMethods: openai-codex, kimi-for-coding, xai (agent) + + anthropic, github-copilot, mastracode-login (terminal, run `mastracode login`) when the client supports terminal auth session/new, nothing configured - succeeds, every model "(provider not configured)" + auth_required session/new, default model's provider not configured - starts on openai/gpt-5.5 with no key, first prompt fails + switches the thread to a signed-in provider's default (e.g. anthropic/claude-fable-5) authenticate - throws + agent method: open browser, wait for callback or device approval, save to auth.json ``` Providers that need typed input (Anthropic's pasted code, Copilot's device code) use the terminal methods; a device URL missing its code fails fast instead of hanging. After a ChatGPT sign-in the memory model is seeded the same way `/login` does it. Zed appends terminal-auth args to the agent command (`mastracode --acp login`), so `login` is recognized after the ACP flags too. ## Related issue(s) COR-1372 ## Type of change - [x] New feature (non-breaking change that adds functionality) ## 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 Verified: SDK and TUI typechecks, 551 SDK tests (ACP, auth, onboarding), 887 TUI tests including the new `mastracode login` tests, and `test:acp:conformance`. Replayed Zed's flow against the built CLI using Zed's `clientCapabilities` and terminal-auth command construction from its source: fresh install gets six methods and `auth_required`, `node cli.js --acp login` saved an Anthropic key, and the retried session started on `anthropic/claude-fable-5`. Against the built CLI with an empty HOME, `session/new` returns `auth_required`, an `OPENAI_API_KEY` lets it start, and the registry's `run_auth_check` passes. A real browser sign-in wasn't run. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Mastra Code can now help ACP-connected editors sign in to supported providers. If the selected model is not available because its provider is not signed in, a new session can use a model from a signed-in provider. ## Summary - ACP initialization advertises browser sign-in for OpenAI Codex, Kimi For Coding, and xAI. It advertises terminal sign-in methods when the client supports terminal authentication. - ACP `authenticate` runs supported browser sign-ins in the server process and saves credentials. Providers that need typed input direct users to `mastracode login`. - `session/new` returns `auth_required` when no usable provider is configured. If another discovered provider has credentials, the session can switch to that provider’s default model. - Added `mastracode login` for provider sign-in or API-key entry. The `--provider` option skips the provider menu. - Kimi and xAI OAuth auth details now include a user code. Provider default memory-model seeding is shared by ACP sign-in and terminal login. ## Validation The PR description reports passing SDK and TUI typechecks, 551 SDK tests, 887 TUI tests, ACP conformance tests, and the registry `run_auth_check`. It also reports manual checks of Zed’s ACP flow and `auth_required` and `OPENAI_API_KEY` behavior. A real browser sign-in was not run. These results were reported by the author and were not independently verified here. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
archasek
added a commit
to archasek/mastra
that referenced
this pull request
Oct 5, 2026
* fix(core): restart evented nested workflows that crashed mid-resume (mastra-ai#25630) Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> * fix(ci): unbreak unit and qdrant store suites under the undici 8 override (mastra-ai#25864) Two CI failures trace back to the same place: forcing undici 8.11.2 repo-wide in mastra-ai#25853. The channel provider tests (telegram 32, teams 9, plus discord 13 which was broken the same way) captured the mock request body with `JSON.parse(String(opts.body))`. undici 8 stopped handing reply callbacks the raw string body — it arrives as a chunk array or async iterable — so the parse threw on "[object Object]" inside the mock reply, the fetch rejected, and the tests hung until the 5s timeout. Reply callbacks are now async and read the body through a small helper: ```ts .reply(200, async opts => { captured = JSON.parse(await readMockBody(opts.body)); return { ok: true, result: true }; }) ``` The qdrant store tests failed with `UND_ERR_INVALID_ARG` because `@qdrant/js-client-rest` imports undici itself and passes an Agent as `dispatcher` to global fetch. That paired an undici 8 dispatcher with the undici 7.x Node bundles for fetch, and undici 8 rejects the handler ("invalid onRequestStart method"). The blanket `undici@<8.11.2: 8.11.2` override ignored the client's declared `^6.24.0` range, so this puts that one consumer back: ```yaml '@qdrant/js-client-rest>undici': 6.29.0 ``` Everything else stays on 8.11.2, and 6.29.0 has no known advisories — though Vanta should sign off on the exemption since their rule was the reason for the blanket pin. Test plan: ran each affected suite locally — telegram 69/69, teams 46/46, discord 63/63, qdrant 235/235 (all red before), with tsc and oxfmt clean on the changed files. No changeset: the test files aren't published, and pnpm-workspace.yaml is repo config. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Undici changed how some test tools provide request data, which caused several tests to fail when they tried to read it. This PR updates the tests to read that data correctly and keeps the Qdrant client on a compatible Undici version. ## Changes - Updated Telegram, Teams, and Discord test callbacks to read request bodies from strings, byte arrays, chunk arrays, and async iterables before parsing them. The helpers join byte chunks before decoding them as UTF-8. - Added a package-specific override so `@qdrant/js-client-rest` uses Undici 6.29.0. Other consumers remain subject to the existing Undici 8.11.2 override. ## Validation The PR author reports that the affected suites pass: Telegram 69/69, Teams 46/46, Discord 63/63, and Qdrant 235/235. The author also reports clean `tsc` and `oxfmt` checks on the changed files. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: mastracode <284800079+mastra-platform[bot]@users.noreply.github.com> * chore: version packages * fix(core): fail closed on output stream processor errors (mastra-ai#25826) > Opened by @user_01KPS2202RYQR4JAMPVXBB9A1H > Opened by @user_01KPS2202RYQR4JAMPVXBB9A1H ## Summary - `ProcessorRunner.processPart` rethrows non-TripWire `processOutputStream` failures instead of returning the original, unprocessed chunk. `abort()`/TripWire behavior is unchanged. - Durable and evented runs now process streamed model chunks inside the LLM step before they are published. A processor failure emits an `error` chunk and ends with `finishReason: 'error'`, and the raw chunk never reaches the run topic. A blocked chunk ends the step with a tripwire, and later chunks are not published. - Durable tool-chunk processor failures fail the tool step before the chunk is published. Pubsub publish failures stay non-fatal. - For durable and evented agents, lifecycle-chunk failures (`start`, `step-start`, `step-finish`, `finish`) error `fullStream` and reject derived output promises instead of hanging. For regular agents, `step-start` and `finish` failures emit an `error` chunk and resolve with `finishReason: 'error'`; `step-finish` errors the stream, and `start` is not passed to output stream processors. - Updated the old fail-open assertions and added regular, durable, and evented regression coverage. - Added an `@mastra/core` patch changeset. ## Test plan - `pnpm test:core` - Focused: `src/agent/durable`, `src/processors`, `src/stream/base`, agent stream-processor and parity tests - `pnpm --filter ./packages/core check` - `pnpm --filter ./packages/core lint` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 If a stream processor fails, the system now stops instead of sending data that was not successfully processed. This prevents unprocessed data from reaching consumers and makes the failure visible to callers. ## Summary - `ProcessorRunner.processPart` now rethrows non-TripWire processor errors instead of returning the original chunk. TripWire behavior remains unchanged. - Durable LLM streams now process chunks before publishing them. Processor errors fail the step, and blocked chunks stop further stream consumption. - Durable tool-result processor errors now fail the tool step before publication. PubSub publish failures remain non-fatal. - Stream drain failures now error active and future evented streams and reject pending output promises. - Added regression tests for regular, durable, and evented streams, lifecycle chunks, tool results, blocking, and publish failures. - Added an `@mastra/core` patch changeset. ## Validation The PR objectives report successful runs of the focused Vitest suite, `pnpm test:core`, `pnpm build:core`, the core type check, and core lint. The reported core test run passed 18,645 tests, skipped 105, and marked 33 as todo. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: NikAiyer <nick.aiyer@gmail.com> Co-authored-by: mastra-platform[bot] <284800079+mastra-platform[bot]@users.noreply.github.com> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> * docs(core): clarify durable observe offsets (mastra-ai#25824) Summary: Clarifies that `DurableAgent.observe()` offsets are inclusive, zero-based PubSub event indices rather than chunk counts. The public docblocks, reference page, and durable-agent guide now describe no-offset replay, unsupported transports, offsets past retained history, and the partial aggregated output produced when earlier deltas are skipped. This is documentation-only and does not change runtime behavior or add a public cursor API. Test plan: Ran the focused `CachingPubSub` test suite (76 tests), the `@mastra/core` typecheck, MDX formatting, Remark, Vale, and the full documentation validation suite. Work item: COR-1317 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This change explains how `DurableAgent.observe()` reconnects to a stream. It clarifies when earlier events are replayed and how skipping events can make the result incomplete. ## Summary - Defines `offset` as an inclusive, zero-based PubSub event index, not a chunk count. - Recommends omitting `offset` to replay available cached events before live events. - Explains that transports without numeric offset support start with live events when an offset is supplied. - Documents replay limits, including disabled or unavailable caching, and explains how offsets beyond retained history affect live delivery. - Warns that skipped events can leave aggregated text partial or structured output incomplete. - Updates API docblocks and durable-agent documentation. No runtime behavior or public cursor API changes are reported. - The PR description reports 76 focused `CachingPubSub` tests, a core typecheck, and documentation validation steps as completed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: NikAiyer <nick.aiyer@gmail.com> Co-authored-by: mastra-platform[bot] <284800079+mastra-platform[bot]@users.noreply.github.com> * fix(memory): stop CPU growth when observational memory is created per request (mastra-ai#25872) Creating a `Memory` with observational memory per request made CPU usage climb steadily until the process was pinned, on Node 22 and earlier. Each `TokenCounter` created its own `AsyncLocalStorage`. On Node's default async_hooks-based ALS (before Node 24), every ALS that has been `run()` stays registered for the life of the process, and every promise or `await` loops over all of them. One new observational memory engine per request meant one permanent registration per request. ```ts // a pattern like this slowly degraded the whole process const agent = new Agent({ // ... memory: ({ requestContext }) => new Memory({ options: { observationalMemory: { /* ... */ } } }), }); ``` This switches to a single shared ALS whose store maps each counter to its model context, so scoping per counter works exactly as before, including concurrent requests on the same or separate counters. On Node 22, after 5k per-request counters, a fixed 20k-await workload took about 7.6s on `@mastra/memory@1.35.0` and about 2ms with this change. Added a regression test that fails on the old implementation, plus tests for per-counter scoping across awaits, nesting, and interleaved concurrent runs. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 When each request creates a new memory counter, the old design added more background tracking work over time on some Node.js versions. This change shares that tracking system while keeping each counter’s model settings separate, including during overlapping requests. ## Changes - Use one module-level `AsyncLocalStorage` to store model contexts keyed by `TokenCounter`. - Copy the current context map when entering a model-context scope, so nested and concurrent scopes keep their settings isolated. - Add tests for storage reuse, context isolation across awaits and nesting, and concurrent runs. - Add a patch changeset for `@mastra/memory`. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * feat(storage): implement span queries [OBS-527] (mastra-ai#25791) Implements [OBS-527](https://linear.app/kepler-crm/issue/OBS-527), the OSS storage layer for the Spans view in [OBS-18](https://linear.app/kepler-crm/issue/OBS-18). Users will be able to find individual matching spans, such as tool calls, across traces. This PR provides backend storage execution; it does not yet enable the feature in Studio. **Included:** `querySpans(plan)` in DuckDB, PostgreSQL v-next, and ClickHouse v-next. Reuses existing scalar span predicates and tables, applies trusted tenant scope, and returns completed spans with cursor pagination ordered by `startedAt` or `endedAt`. Selects page identities before loading bounded input/output previews and model cost, preserving zero, missing, and unavailable cost states. Adds execution limits, capability advertising, shared conformance tests, documentation, and changesets. ```ts const plan = planSpanQuery({ timeRange: { from: '2026-10-01T00:00:00Z', to: '2026-10-02T00:00:00Z' }, where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'tool_call' } }, page: { limit: 50 }, }); const result = await observabilityStorage.querySpans(plan); ``` **Follow-ups:** [OBS-528](https://linear.app/kepler-crm/issue/OBS-528) implements and validates Platform/MOBS parity; [OBS-529](https://linear.app/kepler-crm/issue/OBS-529) adds server routes and client SDK support; [OBS-521](https://linear.app/kepler-crm/issue/OBS-521) builds the Studio view and wires refresh/detail interactions. Full span payloads use the existing detail API. Nested-attribute filtering depends on [OBS-357](https://linear.app/kepler-crm/issue/OBS-357). **Pagination boundary:** the cursor continues through sorted search results; it does not track new arrivals or provide a snapshot across requests. Manual or automatic refresh can restart the search. Incremental live updates/delta polling would be a separate follow-up if required. This PR adds no search table or materialized view; further physical optimization depends on representative benchmarks. **Validation:** 292 focused tests passed across Core and the three stores, including local PostgreSQL and ClickHouse integration tests. Core/store typechecks, package lint, and focused documentation checks passed. Platform load and replication validation remain part of OBS-528. Stacked on mastra-ai#25701 (OBS-526), which is this PR's base branch. This completes the storage implementation step, not the full OBS-18 rollout. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR adds a way for storage systems to find individual completed spans across traces. It returns matching span summaries in pages, with small input/output previews and model cost, so callers can inspect spans without loading full trace details. ## What changed - Added the `querySpans(plan)` storage API and the `span-query` capability. DuckDB, PostgreSQL v-next, and ClickHouse v-next implement the query. - Reused scalar span predicates and trusted tenant scope. The stores select completed span records, sort and paginate them with cursors, then load bounded previews and model cost for the page. - Added query time and resource limits, shared storage conformance tests, store-specific tests, documentation, and package changesets. - Generalized trace-query timeout, cursor, and resource-limit error messages by removing “trace.” Error codes remain unchanged. ## Scope and limitations - This adds storage support. It does not enable the feature in Studio or add server routes or client SDK support. - Full span payloads remain available through the existing detail API. Nested-attribute filtering depends on OBS-357. - Pagination does not track new arrivals or provide a snapshot across requests. The PR adds no search table or materialized view. - Platform load and replication validation, server routes and client SDK support, and the Studio view are separate planned work. ## Validation The PR objectives report 292 focused tests passed across Core and the three stores, including local PostgreSQL and ClickHouse integration tests. They also report passing Core/store typechecks, package lint, and focused documentation checks. These results were not independently verified here. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * fix(memory): observe the unbuffered tail when OM activation leaves context over the threshold (mastra-ai#25060) ## Description With async buffering on, when a step crossed `messageTokens`, Observational Memory activated buffered chunks and returned right away without checking whether that was enough. If a big tool result showed up after buffering stopped (e.g. an ~80k-token tool batch), it wasn't in any chunk, so it stayed unobserved and the next model call could blow past the context window ("prompt is too long", then an empty completion after retries). Activation was also sized from the previous step's saved pending count, so it activated fewer chunks than it should have. Now the threshold step keeps activating remaining chunks while it's still over the threshold, then runs a sync observation on whatever's left. Every chunk is activated before the Observer runs, so it only sees messages no chunk has covered — no double observations and `lastObservedAt` never moves backwards. Cleanup removes both activated and observed messages. `activate()` takes an optional fresh `pendingTokens` (and uses the count it already computes under `checkThreshold`). The docs/TSDoc sentence saying sync observation only runs when "buffered activation did not happen" is updated to match. The newest large tool result itself stays in context (retention floor keeps it); what gets compacted is the older history. `finalize()` has a similar activate-once-then-observe shape and is left for a follow-up. New tests in `threshold-activation-tail.test.ts` use real OM + in-memory storage (only the Observer call is mocked); the first two fail on `main`. ## Related issue(s) Fixes mastra-ai#19767 ## 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 - [x] Test update ## 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 - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 When activating stored notes does not make the conversation small enough, this change handles the remaining messages before the next AI request. This helps prevent oversized requests from failing. ## Summary - Threshold handling now recalculates pending tokens as it activates buffered chunks. If pending tokens remain at or above the threshold, it synchronously observes the uncovered messages. - `activate()` accepts a live `pendingTokens` count so activation sizing can use current data instead of stale persisted data. - Cleanup includes messages handled by activation and synchronous observation. If observation fails under the `continue` policy, activated messages are still cleaned up. - Documentation and a patch changeset describe the updated behavior. Tests cover the unbuffered tail, multiple activations, observer failure, and activation that brings pending tokens below the threshold. - The goal-judge fixture and request matcher were updated for the changed follow-up request. Test execution results were not provided. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * chore: regenerate providers and docs [skip ci] * fix(code-sdk): drain ACP dispatch before closing runtime resources (mastra-ai#25875) ACP sessions could keep notification dispatch running after shutdown and close PubSub while workers were still using it. This stops producers and the scheduler first, gives dispatch up to 2 seconds to drain, then settles consumers before closing PubSub and storage. Cleanup remains best-effort within the existing 10-second disposal cap. Before (simplified): ```ts await Promise.allSettled([stopWorkers(), pubSub.close()]); await storage.close(); // notification dispatch still running ``` After (simplified): ```ts stopProducersAndScheduler(); await drainNotificationDispatch({ graceMs: 2_000 }); await settleConsumers(); await pubSub.close(); await storage.close(); ``` Verified with 116 ACP tests, 23 scheduler tests, ACP and SDK typechecks, lint, and build. Live red/green runs cover EOF, SIGINT, SIGTERM, MCP startup failure, deferred workers, and hung cleanup. A timed-out dispatcher isn't cancelled; residual core PID metadata is unchanged. Includes a code-sdk patch changeset. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 The PR changes shutdown so pending notifications can finish before the system closes the resources they need. This helps prevent shutdown from interrupting that work. ## Changes - Stop session producers and providers, then allow notification dispatch up to two seconds to drain. - Wait for thread-lock release, MCP disconnection, worker shutdown, and interval shutdown before closing PubSub and storage. - Continue teardown when cleanup hooks fail, and share concurrent cleanup calls. - Add tests for shutdown ordering, dispatch timeouts, cleanup failures, and scheduler shutdown during an in-flight prompt. - Add a patch changeset for `@mastra/code-sdk`. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * chore: regenerate providers and docs [skip ci] * feat(playground-ui): show a caret on sidebar links that open a takeover view (mastra-ai#25868) * fix(playground-ui): keep spacing even in RelativeTimestamp labels (mastra-ai#25867) * fix(factory-ui): unify review card action states (mastra-ai#25836) **─────── TLDR ───────** > A busy Factory card no longer offers a second run: its button, menu, drag and global search all wait for the current run to let go. Clicking Review moved the card but left Review clickable beside "Starting an automated run…", because the button only looked at session activity. Every surface now reads one owner per card (you, automation, a session, or nobody), and only a card nobody holds can start a run. ### Behavior changed you click Review on a card ├─ **was** — Review stays clickable beside "Starting an automated run…" └─ **now** — disabled "Moving…", then "Starting…", then Open session automation works on a card: a sync, a queued run, an automatic retry ├─ **was** — run button clickable, status row saying something else └─ **now** — disabled button naming the work, same words as the row a run or automation holds the card, you open its menu ├─ **was** — every action enabled └─ **now** — run-starting actions disabled, Close and Mark done stay you drag a held card into a working lane, or pick it in global search ├─ **was** — the move or the session went through └─ **now** — refused: "Another run can't start while this card is busy." your own move, run or retry is in flight ├─ **was** — dimmed and drag-locked for some of them only └─ **now** — every one dims the card and locks drag, menu and Remove ### Decisions - **a parked session still holds the card** — a run button beside it starts a rival run; `sessionIsLive` in the owner check undoes it - **a held card can still move into resting or terminal lanes** — closing or finishing starts nothing; `canMoveTo` is one line to tighten - **no ring during "Starting…"** — the ring is the session's status and none exists yet; the row and the disabled button already say it ### Shape changed | | | | |---|---|---| | **−** | `boardCardStatus` | status only, so every button and menu re-derived "busy" | | **−** | `runButton({ running, waiting })` | its two flags missed queued automation: the bug | | **+** | `boardCardState(input)` | one pass returns status row, owner and ring | | **+** | `BoardCardOwner` | who holds the card; drives buttons, menus, drag | | **+** | `canStartRun` · `canMoveTo` | the one rule menu, drag and search share | | **~** | `DragPayload` | a work item carries its `ownerKind` | what the card reads now `boardCardState(input): { status, owner, wick }` · `canMoveTo(ownerKind, phaseKind)` · `BUSY_CARD_MOVE_REFUSAL` ### Not verified - [ ] a real Factory with live automation; only the MSW suites drive these states - [ ] the server refusing a rival run itself; menu, drag and search are client-side gates --- > ██████████████████ **tests** `+672 −52` > ███████████ **source** `+400 −269` — net +131 > █ **changeset** `+7` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Factory cards now show who is using them and what is happening. This helps prevent people from starting duplicate work or moving a card in a way that conflicts with work already in progress. ## Summary - Added `boardCardState` to derive each card’s status, owner, and session activity. - Updated card actions and menus to reflect card ownership. Run-starting actions are blocked while a card is held. Remove and Dismiss suggested run are blocked during the current user’s in-flight move, run, or retry. - Blocked conflicting drag-and-drop and global-search actions, with a busy-card message. Allowed moves that do not start a run when the destination phase permits them. - Awaited work-item and factory-decision query invalidations after successful transitions. - Added MSW-backed tests for review-card lifecycle, menu states, drag-and-drop, and global-search behavior. ## Validation The supplied context reports that the described states were exercised with MSW suites. It does not report test execution results. It also notes that validation did not cover a live Factory with active automation or server-side refusal of a competing run. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * fix(playground): preserve QueryClient across rerenders (mastra-ai#25840) ## Description When `PlaygroundQueryClient` rerenders, it creates a new QueryClient with an empty cache. Initialize it with `useState(() => new QueryClient(...))` so each mounted provider keeps its client, with the existing option merging and retry defaults. Add an MSW regression test that fetches through the real Mastra client, rerenders the provider, and verifies the response remains cached. The test failed before the fix and passes afterward. Impact was measured using the real Playground `AppWrapper` and hooks in jsdom with MSW network responses. Loading Settings, changing the theme, navigating to Agents, returning to Settings and saving request headers, then returning to Agents created one QueryClient and made 25 HTTP requests with both implementations. The provider rendered once throughout these flows, so no request or client-allocation reduction was observed in normal usage tested. In a separate controlled step, explicitly rerendering the app root exposed an empty provided cache with the original implementation (15 cached queries became 0) while the fix retained all 15. Reading the same fresh diagnostic query afterward made one extra request with the original implementation and zero with the fix. This demonstrates cache preservation if the provider rerenders; no equivalent normal-use trigger was found in the current app root. No latency or CPU improvement is claimed. Validation: `pnpm --filter ./packages/playground test:run` passes (327 files, 2,388 tests passed, 2 skipped), as does `pnpm --filter ./packages/playground typecheck`. A scoped typecheck including the new test and fixture and formatting/lint checks on the changed files also pass. Lint reports only the existing warning for `export *` in the provider module. An empty changeset records that this private Playground change needs no package release and satisfies the release-plan check; no `@internal/playground` release entry is added. ## Related issue(s) No linked GitHub issue; requested as a small cache hardening fix. ## 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 - [x] I have made corresponding changes to the documentation (if applicable; no documentation change needed) - [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 The playground now keeps the same query client when its provider rerenders. This keeps fetched data available and prevents repeat requests caused by losing the cache. ## Changes - `PlaygroundQueryClient` now creates its `QueryClient` with lazy `useState`. Existing option merging and retry defaults remain unchanged. - Added a system-packages fixture and an MSW regression test. The test fetches packages through the Mastra client, rerenders the provider, and checks that the response remains cached. ## Validation The author reports that the playground test suite passed: 327 files and 2,388 tests passed, with 2 skipped. The author also reports that typecheck passed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * chore: version packages * chore: regenerate providers and docs [skip ci] * fix: contain thread-ID signal socket paths (mastra-ai#25876) ## Summary PR mastra-ai#25758 validated foreign thread IDs before using them as socket file names, but only when cross-project discovery was enabled. With it off, a hostile `threadId` (e.g. `../../mcesc`) could still create or unlink a `.sock` file outside the socket root. This validates the thread ID at the socket-path boundary for every thread topic (own or foreign resource, sharing on or off, including idle-acceptance suffixed topics). It also rejects thread IDs that would reuse another socket's file name in the same directory: `.leases` and the sanitized peer/owner discovery topics. Ordinary punctuation, spaces and Unicode in thread IDs keep working. ## Not in scope Unsafe `resourceId` values keep their existing behavior (foreign IDs fall back to the local resource directory; unsafe own IDs are unchanged). Changing that policy is a compatibility decision for a follow-up. ## Test plan - `signals-pubsub.test.ts` covers own/foreign threads, sharing on/off, idle-acceptance suffix, reserved names, and safe punctuation/Unicode. - SDK lint and typecheck pass. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This change stops thread names from creating socket files in the wrong place or taking the place of sockets used for leases and discovery. It still allows normal names with spaces, punctuation, and Unicode. ## Changes - Validate thread IDs whenever a thread topic is mapped to a socket path, whether the thread belongs to this resource or another and whether shared discovery is enabled or not. - Reject path separators, control characters, `.` and `..`, and names that collide with lease or peer/owner discovery sockets. Check reserved names without regard to case. - Keep existing `resourceId` handling unchanged. - Add tests for rejected IDs, idle-acceptance topics, socket collisions, and supported punctuation and Unicode. Add a patch changeset for `@mastra/code-sdk`. ## Validation status The PR description reports that SDK lint and typecheck pass. It also reports a failing-tests label. Test completion status is not established by the supplied evidence. Current review findings and severity counts were not supplied. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * chore: regenerate providers and docs [skip ci] * chore: version packages * chore: regenerate providers and docs [skip ci] * chore: regenerate providers and docs [skip ci] * feat(code-sdk): sign in from ACP clients (mastra-ai#25871) ## Description ACP clients can now sign in to Mastra Code without leaving the editor. `initialize` advertises browser sign-in for ChatGPT, Kimi For Coding, and xAI, which `authenticate` runs in-process. Clients that advertise terminal auth also get Claude and GitHub Copilot sign-in (`mastracode login --provider <id>`) and `mastracode-login` (`mastracode login`) for any other provider or an API key. The new command exits when sign-in finishes. `session/new` returns `auth_required` when no provider is configured, so clients surface those options. This is what the ACP registry requires to list Mastra Code (agentclientprotocol/registry#651). ```diff initialize - (no authMethods) + authMethods: openai-codex, kimi-for-coding, xai (agent) + + anthropic, github-copilot, mastracode-login (terminal, run `mastracode login`) when the client supports terminal auth session/new, nothing configured - succeeds, every model "(provider not configured)" + auth_required session/new, default model's provider not configured - starts on openai/gpt-5.5 with no key, first prompt fails + switches the thread to a signed-in provider's default (e.g. anthropic/claude-fable-5) authenticate - throws + agent method: open browser, wait for callback or device approval, save to auth.json ``` Providers that need typed input (Anthropic's pasted code, Copilot's device code) use the terminal methods; a device URL missing its code fails fast instead of hanging. After a ChatGPT sign-in the memory model is seeded the same way `/login` does it. Zed appends terminal-auth args to the agent command (`mastracode --acp login`), so `login` is recognized after the ACP flags too. ## Related issue(s) COR-1372 ## Type of change - [x] New feature (non-breaking change that adds functionality) ## 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 Verified: SDK and TUI typechecks, 551 SDK tests (ACP, auth, onboarding), 887 TUI tests including the new `mastracode login` tests, and `test:acp:conformance`. Replayed Zed's flow against the built CLI using Zed's `clientCapabilities` and terminal-auth command construction from its source: fresh install gets six methods and `auth_required`, `node cli.js --acp login` saved an Anthropic key, and the retried session started on `anthropic/claude-fable-5`. Against the built CLI with an empty HOME, `session/new` returns `auth_required`, an `OPENAI_API_KEY` lets it start, and the registry's `run_auth_check` passes. A real browser sign-in wasn't run. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Mastra Code can now help ACP-connected editors sign in to supported providers. If the selected model is not available because its provider is not signed in, a new session can use a model from a signed-in provider. ## Summary - ACP initialization advertises browser sign-in for OpenAI Codex, Kimi For Coding, and xAI. It advertises terminal sign-in methods when the client supports terminal authentication. - ACP `authenticate` runs supported browser sign-ins in the server process and saves credentials. Providers that need typed input direct users to `mastracode login`. - `session/new` returns `auth_required` when no usable provider is configured. If another discovered provider has credentials, the session can switch to that provider’s default model. - Added `mastracode login` for provider sign-in or API-key entry. The `--provider` option skips the provider menu. - Kimi and xAI OAuth auth details now include a user code. Provider default memory-model seeding is shared by ACP sign-in and terminal login. ## Validation The PR description reports passing SDK and TUI typechecks, 551 SDK tests, 887 TUI tests, ACP conformance tests, and the registry `run_auth_check`. It also reports manual checks of Zed’s ACP flow and `auth_required` and `OPENAI_API_KEY` behavior. A real browser sign-in was not run. These results were reported by the author and were not independently verified here. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * chore: regenerate providers and docs [skip ci] * fix(mastra-code): persist login and bound ACP agent compatibility [skip cd] * chore(ci): park inherited workflow triggers for manual qualification [skip cd] * fix(mastra-code): authenticate restored sessions and select available models [skip cd] * fix(mastracode): report native Codex model inventory * docs(changeset): record native model inventory fix * fix(mastracode): keep machine model inventory offline --------- Co-authored-by: mastra-platform[bot] <284800079+mastra-platform[bot]@users.noreply.github.com> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> Co-authored-by: NikAiyer <nick.aiyer@gmail.com> Co-authored-by: dane-ai-mastra[bot] <199668360+dane-ai-mastra[bot]@users.noreply.github.com> Co-authored-by: Tyler Barnes <tylerdbarnes@gmail.com> Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> Co-authored-by: Anurag Ojha <aojharaj2004@gmail.com> Co-authored-by: Justin Levine <20596508+jal-co@users.noreply.github.com> Co-authored-by: Damien Schneider <74979845+damien-schneider@users.noreply.github.com>
archasek
added a commit
to archasek/mastra
that referenced
this pull request
Oct 6, 2026
…gin [skip cd] * fix(core): restart evented nested workflows that crashed mid-resume (mastra-ai#25630) Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> * fix(ci): unbreak unit and qdrant store suites under the undici 8 override (mastra-ai#25864) Two CI failures trace back to the same place: forcing undici 8.11.2 repo-wide in mastra-ai#25853. The channel provider tests (telegram 32, teams 9, plus discord 13 which was broken the same way) captured the mock request body with `JSON.parse(String(opts.body))`. undici 8 stopped handing reply callbacks the raw string body — it arrives as a chunk array or async iterable — so the parse threw on "[object Object]" inside the mock reply, the fetch rejected, and the tests hung until the 5s timeout. Reply callbacks are now async and read the body through a small helper: ```ts .reply(200, async opts => { captured = JSON.parse(await readMockBody(opts.body)); return { ok: true, result: true }; }) ``` The qdrant store tests failed with `UND_ERR_INVALID_ARG` because `@qdrant/js-client-rest` imports undici itself and passes an Agent as `dispatcher` to global fetch. That paired an undici 8 dispatcher with the undici 7.x Node bundles for fetch, and undici 8 rejects the handler ("invalid onRequestStart method"). The blanket `undici@<8.11.2: 8.11.2` override ignored the client's declared `^6.24.0` range, so this puts that one consumer back: ```yaml '@qdrant/js-client-rest>undici': 6.29.0 ``` Everything else stays on 8.11.2, and 6.29.0 has no known advisories — though Vanta should sign off on the exemption since their rule was the reason for the blanket pin. Test plan: ran each affected suite locally — telegram 69/69, teams 46/46, discord 63/63, qdrant 235/235 (all red before), with tsc and oxfmt clean on the changed files. No changeset: the test files aren't published, and pnpm-workspace.yaml is repo config. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Undici changed how some test tools provide request data, which caused several tests to fail when they tried to read it. This PR updates the tests to read that data correctly and keeps the Qdrant client on a compatible Undici version. ## Changes - Updated Telegram, Teams, and Discord test callbacks to read request bodies from strings, byte arrays, chunk arrays, and async iterables before parsing them. The helpers join byte chunks before decoding them as UTF-8. - Added a package-specific override so `@qdrant/js-client-rest` uses Undici 6.29.0. Other consumers remain subject to the existing Undici 8.11.2 override. ## Validation The PR author reports that the affected suites pass: Telegram 69/69, Teams 46/46, Discord 63/63, and Qdrant 235/235. The author also reports clean `tsc` and `oxfmt` checks on the changed files. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: mastracode <284800079+mastra-platform[bot]@users.noreply.github.com> * chore: version packages * fix(core): fail closed on output stream processor errors (mastra-ai#25826) > Opened by @user_01KPS2202RYQR4JAMPVXBB9A1H > Opened by @user_01KPS2202RYQR4JAMPVXBB9A1H ## Summary - `ProcessorRunner.processPart` rethrows non-TripWire `processOutputStream` failures instead of returning the original, unprocessed chunk. `abort()`/TripWire behavior is unchanged. - Durable and evented runs now process streamed model chunks inside the LLM step before they are published. A processor failure emits an `error` chunk and ends with `finishReason: 'error'`, and the raw chunk never reaches the run topic. A blocked chunk ends the step with a tripwire, and later chunks are not published. - Durable tool-chunk processor failures fail the tool step before the chunk is published. Pubsub publish failures stay non-fatal. - For durable and evented agents, lifecycle-chunk failures (`start`, `step-start`, `step-finish`, `finish`) error `fullStream` and reject derived output promises instead of hanging. For regular agents, `step-start` and `finish` failures emit an `error` chunk and resolve with `finishReason: 'error'`; `step-finish` errors the stream, and `start` is not passed to output stream processors. - Updated the old fail-open assertions and added regular, durable, and evented regression coverage. - Added an `@mastra/core` patch changeset. ## Test plan - `pnpm test:core` - Focused: `src/agent/durable`, `src/processors`, `src/stream/base`, agent stream-processor and parity tests - `pnpm --filter ./packages/core check` - `pnpm --filter ./packages/core lint` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 If a stream processor fails, the system now stops instead of sending data that was not successfully processed. This prevents unprocessed data from reaching consumers and makes the failure visible to callers. ## Summary - `ProcessorRunner.processPart` now rethrows non-TripWire processor errors instead of returning the original chunk. TripWire behavior remains unchanged. - Durable LLM streams now process chunks before publishing them. Processor errors fail the step, and blocked chunks stop further stream consumption. - Durable tool-result processor errors now fail the tool step before publication. PubSub publish failures remain non-fatal. - Stream drain failures now error active and future evented streams and reject pending output promises. - Added regression tests for regular, durable, and evented streams, lifecycle chunks, tool results, blocking, and publish failures. - Added an `@mastra/core` patch changeset. ## Validation The PR objectives report successful runs of the focused Vitest suite, `pnpm test:core`, `pnpm build:core`, the core type check, and core lint. The reported core test run passed 18,645 tests, skipped 105, and marked 33 as todo. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: NikAiyer <nick.aiyer@gmail.com> Co-authored-by: mastra-platform[bot] <284800079+mastra-platform[bot]@users.noreply.github.com> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> * docs(core): clarify durable observe offsets (mastra-ai#25824) Summary: Clarifies that `DurableAgent.observe()` offsets are inclusive, zero-based PubSub event indices rather than chunk counts. The public docblocks, reference page, and durable-agent guide now describe no-offset replay, unsupported transports, offsets past retained history, and the partial aggregated output produced when earlier deltas are skipped. This is documentation-only and does not change runtime behavior or add a public cursor API. Test plan: Ran the focused `CachingPubSub` test suite (76 tests), the `@mastra/core` typecheck, MDX formatting, Remark, Vale, and the full documentation validation suite. Work item: COR-1317 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This change explains how `DurableAgent.observe()` reconnects to a stream. It clarifies when earlier events are replayed and how skipping events can make the result incomplete. ## Summary - Defines `offset` as an inclusive, zero-based PubSub event index, not a chunk count. - Recommends omitting `offset` to replay available cached events before live events. - Explains that transports without numeric offset support start with live events when an offset is supplied. - Documents replay limits, including disabled or unavailable caching, and explains how offsets beyond retained history affect live delivery. - Warns that skipped events can leave aggregated text partial or structured output incomplete. - Updates API docblocks and durable-agent documentation. No runtime behavior or public cursor API changes are reported. - The PR description reports 76 focused `CachingPubSub` tests, a core typecheck, and documentation validation steps as completed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: NikAiyer <nick.aiyer@gmail.com> Co-authored-by: mastra-platform[bot] <284800079+mastra-platform[bot]@users.noreply.github.com> * fix(memory): stop CPU growth when observational memory is created per request (mastra-ai#25872) Creating a `Memory` with observational memory per request made CPU usage climb steadily until the process was pinned, on Node 22 and earlier. Each `TokenCounter` created its own `AsyncLocalStorage`. On Node's default async_hooks-based ALS (before Node 24), every ALS that has been `run()` stays registered for the life of the process, and every promise or `await` loops over all of them. One new observational memory engine per request meant one permanent registration per request. ```ts // a pattern like this slowly degraded the whole process const agent = new Agent({ // ... memory: ({ requestContext }) => new Memory({ options: { observationalMemory: { /* ... */ } } }), }); ``` This switches to a single shared ALS whose store maps each counter to its model context, so scoping per counter works exactly as before, including concurrent requests on the same or separate counters. On Node 22, after 5k per-request counters, a fixed 20k-await workload took about 7.6s on `@mastra/memory@1.35.0` and about 2ms with this change. Added a regression test that fails on the old implementation, plus tests for per-counter scoping across awaits, nesting, and interleaved concurrent runs. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 When each request creates a new memory counter, the old design added more background tracking work over time on some Node.js versions. This change shares that tracking system while keeping each counter’s model settings separate, including during overlapping requests. ## Changes - Use one module-level `AsyncLocalStorage` to store model contexts keyed by `TokenCounter`. - Copy the current context map when entering a model-context scope, so nested and concurrent scopes keep their settings isolated. - Add tests for storage reuse, context isolation across awaits and nesting, and concurrent runs. - Add a patch changeset for `@mastra/memory`. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * feat(storage): implement span queries [OBS-527] (mastra-ai#25791) Implements [OBS-527](https://linear.app/kepler-crm/issue/OBS-527), the OSS storage layer for the Spans view in [OBS-18](https://linear.app/kepler-crm/issue/OBS-18). Users will be able to find individual matching spans, such as tool calls, across traces. This PR provides backend storage execution; it does not yet enable the feature in Studio. **Included:** `querySpans(plan)` in DuckDB, PostgreSQL v-next, and ClickHouse v-next. Reuses existing scalar span predicates and tables, applies trusted tenant scope, and returns completed spans with cursor pagination ordered by `startedAt` or `endedAt`. Selects page identities before loading bounded input/output previews and model cost, preserving zero, missing, and unavailable cost states. Adds execution limits, capability advertising, shared conformance tests, documentation, and changesets. ```ts const plan = planSpanQuery({ timeRange: { from: '2026-10-01T00:00:00Z', to: '2026-10-02T00:00:00Z' }, where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'tool_call' } }, page: { limit: 50 }, }); const result = await observabilityStorage.querySpans(plan); ``` **Follow-ups:** [OBS-528](https://linear.app/kepler-crm/issue/OBS-528) implements and validates Platform/MOBS parity; [OBS-529](https://linear.app/kepler-crm/issue/OBS-529) adds server routes and client SDK support; [OBS-521](https://linear.app/kepler-crm/issue/OBS-521) builds the Studio view and wires refresh/detail interactions. Full span payloads use the existing detail API. Nested-attribute filtering depends on [OBS-357](https://linear.app/kepler-crm/issue/OBS-357). **Pagination boundary:** the cursor continues through sorted search results; it does not track new arrivals or provide a snapshot across requests. Manual or automatic refresh can restart the search. Incremental live updates/delta polling would be a separate follow-up if required. This PR adds no search table or materialized view; further physical optimization depends on representative benchmarks. **Validation:** 292 focused tests passed across Core and the three stores, including local PostgreSQL and ClickHouse integration tests. Core/store typechecks, package lint, and focused documentation checks passed. Platform load and replication validation remain part of OBS-528. Stacked on mastra-ai#25701 (OBS-526), which is this PR's base branch. This completes the storage implementation step, not the full OBS-18 rollout. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR adds a way for storage systems to find individual completed spans across traces. It returns matching span summaries in pages, with small input/output previews and model cost, so callers can inspect spans without loading full trace details. ## What changed - Added the `querySpans(plan)` storage API and the `span-query` capability. DuckDB, PostgreSQL v-next, and ClickHouse v-next implement the query. - Reused scalar span predicates and trusted tenant scope. The stores select completed span records, sort and paginate them with cursors, then load bounded previews and model cost for the page. - Added query time and resource limits, shared storage conformance tests, store-specific tests, documentation, and package changesets. - Generalized trace-query timeout, cursor, and resource-limit error messages by removing “trace.” Error codes remain unchanged. ## Scope and limitations - This adds storage support. It does not enable the feature in Studio or add server routes or client SDK support. - Full span payloads remain available through the existing detail API. Nested-attribute filtering depends on OBS-357. - Pagination does not track new arrivals or provide a snapshot across requests. The PR adds no search table or materialized view. - Platform load and replication validation, server routes and client SDK support, and the Studio view are separate planned work. ## Validation The PR objectives report 292 focused tests passed across Core and the three stores, including local PostgreSQL and ClickHouse integration tests. They also report passing Core/store typechecks, package lint, and focused documentation checks. These results were not independently verified here. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * fix(memory): observe the unbuffered tail when OM activation leaves context over the threshold (mastra-ai#25060) ## Description With async buffering on, when a step crossed `messageTokens`, Observational Memory activated buffered chunks and returned right away without checking whether that was enough. If a big tool result showed up after buffering stopped (e.g. an ~80k-token tool batch), it wasn't in any chunk, so it stayed unobserved and the next model call could blow past the context window ("prompt is too long", then an empty completion after retries). Activation was also sized from the previous step's saved pending count, so it activated fewer chunks than it should have. Now the threshold step keeps activating remaining chunks while it's still over the threshold, then runs a sync observation on whatever's left. Every chunk is activated before the Observer runs, so it only sees messages no chunk has covered — no double observations and `lastObservedAt` never moves backwards. Cleanup removes both activated and observed messages. `activate()` takes an optional fresh `pendingTokens` (and uses the count it already computes under `checkThreshold`). The docs/TSDoc sentence saying sync observation only runs when "buffered activation did not happen" is updated to match. The newest large tool result itself stays in context (retention floor keeps it); what gets compacted is the older history. `finalize()` has a similar activate-once-then-observe shape and is left for a follow-up. New tests in `threshold-activation-tail.test.ts` use real OM + in-memory storage (only the Observer call is mocked); the first two fail on `main`. ## Related issue(s) Fixes mastra-ai#19767 ## 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 - [x] Test update ## 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 - [ ] I have addressed all Coderabbit comments on this PR <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 When activating stored notes does not make the conversation small enough, this change handles the remaining messages before the next AI request. This helps prevent oversized requests from failing. ## Summary - Threshold handling now recalculates pending tokens as it activates buffered chunks. If pending tokens remain at or above the threshold, it synchronously observes the uncovered messages. - `activate()` accepts a live `pendingTokens` count so activation sizing can use current data instead of stale persisted data. - Cleanup includes messages handled by activation and synchronous observation. If observation fails under the `continue` policy, activated messages are still cleaned up. - Documentation and a patch changeset describe the updated behavior. Tests cover the unbuffered tail, multiple activations, observer failure, and activation that brings pending tokens below the threshold. - The goal-judge fixture and request matcher were updated for the changed follow-up request. Test execution results were not provided. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * chore: regenerate providers and docs [skip ci] * fix(code-sdk): drain ACP dispatch before closing runtime resources (mastra-ai#25875) ACP sessions could keep notification dispatch running after shutdown and close PubSub while workers were still using it. This stops producers and the scheduler first, gives dispatch up to 2 seconds to drain, then settles consumers before closing PubSub and storage. Cleanup remains best-effort within the existing 10-second disposal cap. Before (simplified): ```ts await Promise.allSettled([stopWorkers(), pubSub.close()]); await storage.close(); // notification dispatch still running ``` After (simplified): ```ts stopProducersAndScheduler(); await drainNotificationDispatch({ graceMs: 2_000 }); await settleConsumers(); await pubSub.close(); await storage.close(); ``` Verified with 116 ACP tests, 23 scheduler tests, ACP and SDK typechecks, lint, and build. Live red/green runs cover EOF, SIGINT, SIGTERM, MCP startup failure, deferred workers, and hung cleanup. A timed-out dispatcher isn't cancelled; residual core PID metadata is unchanged. Includes a code-sdk patch changeset. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 The PR changes shutdown so pending notifications can finish before the system closes the resources they need. This helps prevent shutdown from interrupting that work. ## Changes - Stop session producers and providers, then allow notification dispatch up to two seconds to drain. - Wait for thread-lock release, MCP disconnection, worker shutdown, and interval shutdown before closing PubSub and storage. - Continue teardown when cleanup hooks fail, and share concurrent cleanup calls. - Add tests for shutdown ordering, dispatch timeouts, cleanup failures, and scheduler shutdown during an in-flight prompt. - Add a patch changeset for `@mastra/code-sdk`. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * chore: regenerate providers and docs [skip ci] * feat(playground-ui): show a caret on sidebar links that open a takeover view (mastra-ai#25868) * fix(playground-ui): keep spacing even in RelativeTimestamp labels (mastra-ai#25867) * fix(factory-ui): unify review card action states (mastra-ai#25836) **─────── TLDR ───────** > A busy Factory card no longer offers a second run: its button, menu, drag and global search all wait for the current run to let go. Clicking Review moved the card but left Review clickable beside "Starting an automated run…", because the button only looked at session activity. Every surface now reads one owner per card (you, automation, a session, or nobody), and only a card nobody holds can start a run. ### Behavior changed you click Review on a card ├─ **was** — Review stays clickable beside "Starting an automated run…" └─ **now** — disabled "Moving…", then "Starting…", then Open session automation works on a card: a sync, a queued run, an automatic retry ├─ **was** — run button clickable, status row saying something else └─ **now** — disabled button naming the work, same words as the row a run or automation holds the card, you open its menu ├─ **was** — every action enabled └─ **now** — run-starting actions disabled, Close and Mark done stay you drag a held card into a working lane, or pick it in global search ├─ **was** — the move or the session went through └─ **now** — refused: "Another run can't start while this card is busy." your own move, run or retry is in flight ├─ **was** — dimmed and drag-locked for some of them only └─ **now** — every one dims the card and locks drag, menu and Remove ### Decisions - **a parked session still holds the card** — a run button beside it starts a rival run; `sessionIsLive` in the owner check undoes it - **a held card can still move into resting or terminal lanes** — closing or finishing starts nothing; `canMoveTo` is one line to tighten - **no ring during "Starting…"** — the ring is the session's status and none exists yet; the row and the disabled button already say it ### Shape changed | | | | |---|---|---| | **−** | `boardCardStatus` | status only, so every button and menu re-derived "busy" | | **−** | `runButton({ running, waiting })` | its two flags missed queued automation: the bug | | **+** | `boardCardState(input)` | one pass returns status row, owner and ring | | **+** | `BoardCardOwner` | who holds the card; drives buttons, menus, drag | | **+** | `canStartRun` · `canMoveTo` | the one rule menu, drag and search share | | **~** | `DragPayload` | a work item carries its `ownerKind` | what the card reads now `boardCardState(input): { status, owner, wick }` · `canMoveTo(ownerKind, phaseKind)` · `BUSY_CARD_MOVE_REFUSAL` ### Not verified - [ ] a real Factory with live automation; only the MSW suites drive these states - [ ] the server refusing a rival run itself; menu, drag and search are client-side gates --- > ██████████████████ **tests** `+672 −52` > ███████████ **source** `+400 −269` — net +131 > █ **changeset** `+7` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Factory cards now show who is using them and what is happening. This helps prevent people from starting duplicate work or moving a card in a way that conflicts with work already in progress. ## Summary - Added `boardCardState` to derive each card’s status, owner, and session activity. - Updated card actions and menus to reflect card ownership. Run-starting actions are blocked while a card is held. Remove and Dismiss suggested run are blocked during the current user’s in-flight move, run, or retry. - Blocked conflicting drag-and-drop and global-search actions, with a busy-card message. Allowed moves that do not start a run when the destination phase permits them. - Awaited work-item and factory-decision query invalidations after successful transitions. - Added MSW-backed tests for review-card lifecycle, menu states, drag-and-drop, and global-search behavior. ## Validation The supplied context reports that the described states were exercised with MSW suites. It does not report test execution results. It also notes that validation did not cover a live Factory with active automation or server-side refusal of a competing run. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * fix(playground): preserve QueryClient across rerenders (mastra-ai#25840) ## Description When `PlaygroundQueryClient` rerenders, it creates a new QueryClient with an empty cache. Initialize it with `useState(() => new QueryClient(...))` so each mounted provider keeps its client, with the existing option merging and retry defaults. Add an MSW regression test that fetches through the real Mastra client, rerenders the provider, and verifies the response remains cached. The test failed before the fix and passes afterward. Impact was measured using the real Playground `AppWrapper` and hooks in jsdom with MSW network responses. Loading Settings, changing the theme, navigating to Agents, returning to Settings and saving request headers, then returning to Agents created one QueryClient and made 25 HTTP requests with both implementations. The provider rendered once throughout these flows, so no request or client-allocation reduction was observed in normal usage tested. In a separate controlled step, explicitly rerendering the app root exposed an empty provided cache with the original implementation (15 cached queries became 0) while the fix retained all 15. Reading the same fresh diagnostic query afterward made one extra request with the original implementation and zero with the fix. This demonstrates cache preservation if the provider rerenders; no equivalent normal-use trigger was found in the current app root. No latency or CPU improvement is claimed. Validation: `pnpm --filter ./packages/playground test:run` passes (327 files, 2,388 tests passed, 2 skipped), as does `pnpm --filter ./packages/playground typecheck`. A scoped typecheck including the new test and fixture and formatting/lint checks on the changed files also pass. Lint reports only the existing warning for `export *` in the provider module. An empty changeset records that this private Playground change needs no package release and satisfies the release-plan check; no `@internal/playground` release entry is added. ## Related issue(s) No linked GitHub issue; requested as a small cache hardening fix. ## 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 - [x] I have made corresponding changes to the documentation (if applicable; no documentation change needed) - [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 The playground now keeps the same query client when its provider rerenders. This keeps fetched data available and prevents repeat requests caused by losing the cache. ## Changes - `PlaygroundQueryClient` now creates its `QueryClient` with lazy `useState`. Existing option merging and retry defaults remain unchanged. - Added a system-packages fixture and an MSW regression test. The test fetches packages through the Mastra client, rerenders the provider, and checks that the response remains cached. ## Validation The author reports that the playground test suite passed: 327 files and 2,388 tests passed, with 2 skipped. The author also reports that typecheck passed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * chore: version packages * chore: regenerate providers and docs [skip ci] * fix: contain thread-ID signal socket paths (mastra-ai#25876) ## Summary PR mastra-ai#25758 validated foreign thread IDs before using them as socket file names, but only when cross-project discovery was enabled. With it off, a hostile `threadId` (e.g. `../../mcesc`) could still create or unlink a `.sock` file outside the socket root. This validates the thread ID at the socket-path boundary for every thread topic (own or foreign resource, sharing on or off, including idle-acceptance suffixed topics). It also rejects thread IDs that would reuse another socket's file name in the same directory: `.leases` and the sanitized peer/owner discovery topics. Ordinary punctuation, spaces and Unicode in thread IDs keep working. ## Not in scope Unsafe `resourceId` values keep their existing behavior (foreign IDs fall back to the local resource directory; unsafe own IDs are unchanged). Changing that policy is a compatibility decision for a follow-up. ## Test plan - `signals-pubsub.test.ts` covers own/foreign threads, sharing on/off, idle-acceptance suffix, reserved names, and safe punctuation/Unicode. - SDK lint and typecheck pass. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This change stops thread names from creating socket files in the wrong place or taking the place of sockets used for leases and discovery. It still allows normal names with spaces, punctuation, and Unicode. ## Changes - Validate thread IDs whenever a thread topic is mapped to a socket path, whether the thread belongs to this resource or another and whether shared discovery is enabled or not. - Reject path separators, control characters, `.` and `..`, and names that collide with lease or peer/owner discovery sockets. Check reserved names without regard to case. - Keep existing `resourceId` handling unchanged. - Add tests for rejected IDs, idle-acceptance topics, socket collisions, and supported punctuation and Unicode. Add a patch changeset for `@mastra/code-sdk`. ## Validation status The PR description reports that SDK lint and typecheck pass. It also reports a failing-tests label. Test completion status is not established by the supplied evidence. Current review findings and severity counts were not supplied. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> * chore: regenerate providers and docs [skip ci] * chore: version packages * chore: regenerate providers and docs [skip ci] * chore: regenerate providers and docs [skip ci] * feat(code-sdk): sign in from ACP clients (mastra-ai#25871) ## Description ACP clients can now sign in to Mastra Code without leaving the editor. `initialize` advertises browser sign-in for ChatGPT, Kimi For Coding, and xAI, which `authenticate` runs in-process. Clients that advertise terminal auth also get Claude and GitHub Copilot sign-in (`mastracode login --provider <id>`) and `mastracode-login` (`mastracode login`) for any other provider or an API key. The new command exits when sign-in finishes. `session/new` returns `auth_required` when no provider is configured, so clients surface those options. This is what the ACP registry requires to list Mastra Code (agentclientprotocol/registry#651). ```diff initialize - (no authMethods) + authMethods: openai-codex, kimi-for-coding, xai (agent) + + anthropic, github-copilot, mastracode-login (terminal, run `mastracode login`) when the client supports terminal auth session/new, nothing configured - succeeds, every model "(provider not configured)" + auth_required session/new, default model's provider not configured - starts on openai/gpt-5.5 with no key, first prompt fails + switches the thread to a signed-in provider's default (e.g. anthropic/claude-fable-5) authenticate - throws + agent method: open browser, wait for callback or device approval, save to auth.json ``` Providers that need typed input (Anthropic's pasted code, Copilot's device code) use the terminal methods; a device URL missing its code fails fast instead of hanging. After a ChatGPT sign-in the memory model is seeded the same way `/login` does it. Zed appends terminal-auth args to the agent command (`mastracode --acp login`), so `login` is recognized after the ACP flags too. ## Related issue(s) COR-1372 ## Type of change - [x] New feature (non-breaking change that adds functionality) ## 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 Verified: SDK and TUI typechecks, 551 SDK tests (ACP, auth, onboarding), 887 TUI tests including the new `mastracode login` tests, and `test:acp:conformance`. Replayed Zed's flow against the built CLI using Zed's `clientCapabilities` and terminal-auth command construction from its source: fresh install gets six methods and `auth_required`, `node cli.js --acp login` saved an Anthropic key, and the retried session started on `anthropic/claude-fable-5`. Against the built CLI with an empty HOME, `session/new` returns `auth_required`, an `OPENAI_API_KEY` lets it start, and the registry's `run_auth_check` passes. A real browser sign-in wasn't run. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 Mastra Code can now help ACP-connected editors sign in to supported providers. If the selected model is not available because its provider is not signed in, a new session can use a model from a signed-in provider. ## Summary - ACP initialization advertises browser sign-in for OpenAI Codex, Kimi For Coding, and xAI. It advertises terminal sign-in methods when the client supports terminal authentication. - ACP `authenticate` runs supported browser sign-ins in the server process and saves credentials. Providers that need typed input direct users to `mastracode login`. - `session/new` returns `auth_required` when no usable provider is configured. If another discovered provider has credentials, the session can switch to that provider’s default model. - Added `mastracode login` for provider sign-in or API-key entry. The `--provider` option skips the provider menu. - Kimi and xAI OAuth auth details now include a user code. Provider default memory-model seeding is shared by ACP sign-in and terminal login. ## Validation The PR description reports passing SDK and TUI typechecks, 551 SDK tests, 887 TUI tests, ACP conformance tests, and the registry `run_auth_check`. It also reports manual checks of Zed’s ACP flow and `auth_required` and `OPENAI_API_KEY` behavior. A real browser sign-in was not run. These results were reported by the author and were not independently verified here. <!-- end of auto-generated comment: release notes by coderabbit.ai --> * chore: regenerate providers and docs [skip ci] * fix(mastra-code): persist login and bound ACP agent compatibility [skip cd] * chore(ci): park inherited workflow triggers for manual qualification [skip cd] * fix(mastra-code): authenticate restored sessions and select available models [skip cd] * fix(mastracode): report native Codex model inventory * docs(changeset): record native model inventory fix * fix(mastracode): keep machine model inventory offline * Expose native model reasoning effort choices [skip cd] * fix(mastra-code): expose native reasoning defaults and preserve successful sign-in [skip cd] --------- Co-authored-by: mastra-platform[bot] <284800079+mastra-platform[bot]@users.noreply.github.com> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com> Co-authored-by: NikAiyer <nick.aiyer@gmail.com> Co-authored-by: dane-ai-mastra[bot] <199668360+dane-ai-mastra[bot]@users.noreply.github.com> Co-authored-by: Tyler Barnes <tylerdbarnes@gmail.com> Co-authored-by: remy-builder[bot] <324360501+remy-builder[bot]@users.noreply.github.com> Co-authored-by: Anurag Ojha <aojharaj2004@gmail.com> Co-authored-by: Justin Levine <20596508+jal-co@users.noreply.github.com> Co-authored-by: Damien Schneider <74979845+damien-schneider@users.noreply.github.com>
jal-co
force-pushed
the
jal/cor-1372-add-mastracode-to-the-acp-registry
branch
from
October 11, 2026 21:59
94d5824 to
f08edc8
Compare
jal-co
marked this pull request as ready for review
October 11, 2026 22:01
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 Mastra Code to the registry, pinned to
mastracode@0.46.0(npx,--acp). That release includes mastra-ai/mastra#25871, soinitializereturnsauthMethods.authenticatemastracode login --provider <id>, andmastracode-loginrunsmastracode loginfor any other provider or an API keysession/newreturnsauth_requireduntil a provider is configuredcurrentColorVerified:
build_registry.py --dry-runpasses, andverify_agents.py --agent mastracode --auth-checkpasses against the publishedmastracode@0.46.0.