Show resolved agent authors in the agent-builder list and detail#17205
Conversation
Stored agents already track an authorId, but the API never resolved it
back into a human-readable identity, so the playground could only show
the raw ID. This wires up server-side author enrichment from the auth
provider through to the agent-builder UI.
- core: add optional getUsers(userIds) batch hook to IUserProvider,
with implementations on CompositeAuthProvider and SimpleAuthProvider
- server: new author-enrichment helper (dedupes IDs, prefers batch
lookup, falls back to per-id getUser, soft-gated on auth provider)
wired into the stored-agents list and get handlers
- schema/SDK: add optional author { id, name?, email?, avatarUrl? }
on StoredAgentResponse, fully additive on the wire
- playground: render the author next to each agent row, and enlarge
the agent avatar so the row hierarchy reads cleanly
No existing tests modified; new coverage at every layer (core auth,
server helper + handler integration, client-js roundtrip, playground
component + MSW page test).
Co-Authored-By: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR triageLinked issue check skipped for core contributor @mfrachet. PR complexity score
Applied label: Changed test gateChanged tests failed against the base branch as expected. Label: |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds optional batch user lookup to auth providers and a server-side author enrichment flow (prepareAuthorEnrichment, attachAuthor) that resolves authors for stored-agent list/get handlers; updates schemas, client types/tests, and UI components to accept and render resolved author data. ChangesAuthor Enrichment for Stored Agents
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Move the resolved author from a sub-block under the description to a sibling column between the description and the favorite button on desktop, so the row reads avatar | name+description | author | favorite in one horizontal sweep. On mobile we still stack the author under the description (above the favorite button) where vertical layout is expected. Co-Authored-By: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
🦋 Changeset detectedLatest commit: 6f601c7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 20 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.changeset/bright-steaks-count.md:
- Around line 2-5: The changeset frontmatter lists '`@mastra/server`',
'`@mastra/client-js`', and '`@mastra/core`' but the body only documents server
behavior; either limit the frontmatter to '`@mastra/server`' or expand the body to
include explicit end-user outcomes for '`@mastra/client-js`' and '`@mastra/core`',
or split into separate changeset files (one per package) so each file's
description applies only to the packages named; update the frontmatter and/or
file body accordingly and ensure each changeset follows the guideline that
description content matches the listed package(s).
In @.changeset/hungry-falcons-go.md:
- Around line 2-4: The changeset frontmatter lists three packages but the
description only documents a core interface addition; update the entry so it is
consistent by either removing '`@mastra/client-js`' and '`@mastra/server`' from the
frontmatter (leaving only '`@mastra/core`') or by expanding the description to
clearly state the user-facing changes introduced to '`@mastra/client-js`' and
'`@mastra/server`' (e.g., API surface, bugfixes, or internal dependency bumps) and
how they affect users; ensure the frontmatter package list and the prose
describe the same set of package changes and follow the changeset formatting
conventions.
In @.changeset/sweet-wasps-relax.md:
- Around line 2-4: The changeset frontmatter lists three packages
('`@mastra/client-js`', '`@mastra/server`', '`@mastra/core`') but the description only
documents a client-side API change; update the frontmatter to match the
documented scope by removing '`@mastra/server`' and '`@mastra/core`' (or
alternatively, expand the file description to include their corresponding
updates if they truly changed), ensuring the frontmatter exactly reflects the
packages described in the body.
In `@client-sdks/client-js/src/resources/stored-agent.test.ts`:
- Line 72: Tests in stored-agent.test.ts use the literal model name "gpt-4" in
model objects; replace those literal names with the repository's approved
placeholder token(s) from docs/src/plugins/remark-model-tokens/models.ts (e.g.,
the token constant used for example model names) wherever model: { provider:
'openai', name: 'gpt-4' } appears (including the instances in the test data
around the create/store agent tests and any other occurrences), ensuring you
import or reference the same placeholder token used across the repo so the test
data follows the placeholder convention.
In
`@packages/playground/src/domains/agent-builder/components/agent-list/__tests__/agent-builder-list.test.tsx`:
- Around line 188-276: The test fixtures in agent-builder-list.test.tsx use
hard-coded model objects (e.g., model: { provider: 'openai', name: 'gpt-4' })
inside the StoredAgentResponse fixtures passed to renderList; replace those
literal model provider/name strings with the corresponding placeholder tokens
exported from the repo's model tokens module (import the token constants and use
them for model.name and provider if available) so all test fixtures reference
the official placeholder tokens rather than hard-coded model names.
In `@packages/playground/src/pages/agent-builder/agents/__tests__/index.test.tsx`:
- Around line 223-224: The current assertions use screen.getByText('Alice Doe')
and screen.getByText('bob@example.com') which can throw when the same text
appears in multiple badge variants; change these to multi-match-safe assertions
by using screen.getAllByText('Alice Doe') and
screen.getAllByText('bob@example.com') and assert that the returned arrays have
length > 0 (or alternatively scope with a container and use
within(container).getByText) so the tests tolerate multiple matching elements.
In `@packages/server/src/server/handlers/author-enrichment.ts`:
- Around line 33-36: The type-guard isUserProvider currently only checks for
getCurrentUser but the code later calls provider.getUser (e.g., in the author
enrichment logic), so update the guard to require getUser as well; change
isUserProvider to check that (p as { getUser?: unknown }).getUser is a
'function' (in addition to any existing checks), and then ensure usage sites
like provider.getUser(...) are safe under this strengthened guard so TypeScript
and runtime won't crash.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7054af19-7223-4a95-8ca1-54178313cd08
📒 Files selected for processing (19)
.changeset/bright-steaks-count.md.changeset/hungry-falcons-go.md.changeset/sweet-wasps-relax.mdclient-sdks/client-js/src/resources/stored-agent.test.tsclient-sdks/client-js/src/route-types.generated.tsclient-sdks/client-js/src/types.tspackages/core/src/auth/interfaces/user.tspackages/core/src/server/composite-auth.test.tspackages/core/src/server/composite-auth.tspackages/core/src/server/simple-auth.test.tspackages/core/src/server/simple-auth.tspackages/playground/src/domains/agent-builder/components/agent-list/__tests__/agent-builder-list.test.tsxpackages/playground/src/domains/agent-builder/components/agent-list/agent-builder-list.tsxpackages/playground/src/pages/agent-builder/agents/__tests__/index.test.tsxpackages/server/src/server/handlers/author-enrichment.test.tspackages/server/src/server/handlers/author-enrichment.tspackages/server/src/server/handlers/stored-agents.test.tspackages/server/src/server/handlers/stored-agents.tspackages/server/src/server/schemas/stored-agents.ts
| '@mastra/server': minor | ||
| '@mastra/client-js': patch | ||
| '@mastra/core': patch | ||
| --- |
There was a problem hiding this comment.
Scope the frontmatter to the package(s) actually described in this entry.
This file’s body documents server behavior, but the frontmatter also bumps @mastra/client-js and @mastra/core, which are described in other changesets. Please keep this entry scoped to the package(s) it explains, or add explicit end-user outcomes for every listed package.
potential_issue
As per coding guidelines: “Check that the description inside the changeset file only applies to the packages listed in the frontmatter.” and “If the changes span multiple packages and each change is different from another, you MUST create multiple changeset files.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.changeset/bright-steaks-count.md around lines 2 - 5, The changeset
frontmatter lists '`@mastra/server`', '`@mastra/client-js`', and '`@mastra/core`' but
the body only documents server behavior; either limit the frontmatter to
'`@mastra/server`' or expand the body to include explicit end-user outcomes for
'`@mastra/client-js`' and '`@mastra/core`', or split into separate changeset files
(one per package) so each file's description applies only to the packages named;
update the frontmatter and/or file body accordingly and ensure each changeset
follows the guideline that description content matches the listed package(s).
| '@mastra/core': minor | ||
| '@mastra/client-js': patch | ||
| '@mastra/server': patch |
There was a problem hiding this comment.
Frontmatter includes packages not covered by the description.
This entry describes a core interface addition, but it also bumps @mastra/client-js and @mastra/server without describing user-facing changes for those packages in this file. Narrow the frontmatter or expand the description so every listed package is represented.
potential_issue
As per coding guidelines: “Check that the description inside the changeset file only applies to the packages listed in the frontmatter.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.changeset/hungry-falcons-go.md around lines 2 - 4, The changeset
frontmatter lists three packages but the description only documents a core
interface addition; update the entry so it is consistent by either removing
'`@mastra/client-js`' and '`@mastra/server`' from the frontmatter (leaving only
'`@mastra/core`') or by expanding the description to clearly state the user-facing
changes introduced to '`@mastra/client-js`' and '`@mastra/server`' (e.g., API
surface, bugfixes, or internal dependency bumps) and how they affect users;
ensure the frontmatter package list and the prose describe the same set of
package changes and follow the changeset formatting conventions.
| '@mastra/client-js': minor | ||
| '@mastra/server': patch | ||
| '@mastra/core': patch |
There was a problem hiding this comment.
Align package bumps with the actual client-focused description.
This changeset describes a @mastra/client-js API addition, but the frontmatter also includes @mastra/server and @mastra/core without corresponding outcomes here. Please keep this file package-scoped to what it documents.
potential_issue
As per coding guidelines: “Do not modify this frontmatter. Check that the description inside the changeset file only applies to the packages listed in the frontmatter.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.changeset/sweet-wasps-relax.md around lines 2 - 4, The changeset
frontmatter lists three packages ('`@mastra/client-js`', '`@mastra/server`',
'`@mastra/core`') but the description only documents a client-side API change;
update the frontmatter to match the documented scope by removing
'`@mastra/server`' and '`@mastra/core`' (or alternatively, expand the file
description to include their corresponding updates if they truly changed),
ensuring the frontmatter exactly reflects the packages described in the body.
| id: 'agent-1', | ||
| name: 'Test Agent', | ||
| instructions: 'You are a helpful assistant', | ||
| model: { provider: 'openai', name: 'gpt-4' }, |
There was a problem hiding this comment.
Potential issue: replace newly added literal model names with repository placeholder tokens.
At Line 72, Line 82, and Line 250, the new test data adds name: 'gpt-4'. Please swap these to the approved placeholder token(s) from docs/src/plugins/remark-model-tokens/models.ts to stay aligned with repo standards.
As per coding guidelines, "**/*.{ts,tsx,md,mdx,json}: When adding model names or IDs to examples, changesets, tests, or comments, use placeholder tokens from docs/src/plugins/remark-model-tokens/models.ts".
Also applies to: 82-82, 250-250
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@client-sdks/client-js/src/resources/stored-agent.test.ts` at line 72, Tests
in stored-agent.test.ts use the literal model name "gpt-4" in model objects;
replace those literal names with the repository's approved placeholder token(s)
from docs/src/plugins/remark-model-tokens/models.ts (e.g., the token constant
used for example model names) wherever model: { provider: 'openai', name:
'gpt-4' } appears (including the instances in the test data around the
create/store agent tests and any other occurrences), ensuring you import or
reference the same placeholder token used across the repo so the test data
follows the placeholder convention.
| it('renders the resolved author name when the server returned `author`', () => { | ||
| const agents: StoredAgentResponse[] = [ | ||
| { | ||
| id: 'a1', | ||
| status: 'active', | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| name: 'Alpha Agent', | ||
| description: 'desc', | ||
| instructions: '', | ||
| model: { provider: 'openai', name: 'gpt-4' }, | ||
| visibility: 'public', | ||
| authorId: 'user-1', | ||
| author: { id: 'user-1', name: 'Alice', avatarUrl: 'https://x/y.png' }, | ||
| }, | ||
| ]; | ||
| renderList({ agents }); | ||
|
|
||
| const authors = screen.getAllByTestId('agent-builder-row-author'); | ||
| expect(authors.length).toBeGreaterThan(0); | ||
| expect(authors.some(node => node.textContent?.includes('Alice'))).toBe(true); | ||
| }); | ||
|
|
||
| it('falls back to email when the resolved author has no name', () => { | ||
| const agents: StoredAgentResponse[] = [ | ||
| { | ||
| id: 'a1', | ||
| status: 'active', | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| name: 'Alpha Agent', | ||
| description: 'desc', | ||
| instructions: '', | ||
| model: { provider: 'openai', name: 'gpt-4' }, | ||
| visibility: 'public', | ||
| authorId: 'user-1', | ||
| author: { id: 'user-1', email: 'alice@example.com' }, | ||
| }, | ||
| ]; | ||
| renderList({ agents }); | ||
|
|
||
| const authors = screen.getAllByTestId('agent-builder-row-author'); | ||
| expect(authors.length).toBeGreaterThan(0); | ||
| expect(authors.some(node => node.textContent?.includes('alice@example.com'))).toBe(true); | ||
| }); | ||
|
|
||
| it('falls back to authorId when no resolved author is present', () => { | ||
| const agents: StoredAgentResponse[] = [ | ||
| { | ||
| id: 'a1', | ||
| status: 'active', | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| name: 'Alpha Agent', | ||
| description: 'desc', | ||
| instructions: '', | ||
| model: { provider: 'openai', name: 'gpt-4' }, | ||
| visibility: 'public', | ||
| authorId: 'user-99', | ||
| }, | ||
| ]; | ||
| renderList({ agents }); | ||
|
|
||
| const authors = screen.getAllByTestId('agent-builder-row-author'); | ||
| expect(authors.length).toBeGreaterThan(0); | ||
| expect(authors.some(node => node.textContent?.includes('user-99'))).toBe(true); | ||
| }); | ||
|
|
||
| it('omits the author block when neither `author` nor `authorId` is present', () => { | ||
| const agents: StoredAgentResponse[] = [ | ||
| { | ||
| id: 'a1', | ||
| status: 'active', | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| name: 'Alpha Agent', | ||
| description: 'desc', | ||
| instructions: '', | ||
| model: { provider: 'openai', name: 'gpt-4' }, | ||
| visibility: 'public', | ||
| }, | ||
| ]; | ||
| renderList({ agents }); | ||
|
|
||
| expect(screen.queryByTestId('agent-builder-row-author')).toBeNull(); | ||
| // Row still renders all other fields. | ||
| expect(screen.getByText('Alpha Agent')).toBeTruthy(); | ||
| expect(screen.getByText('desc')).toBeTruthy(); | ||
| }); |
There was a problem hiding this comment.
Replace hard-coded model names with repo model placeholder tokens.
The new test fixtures still use literal model names. Please switch these to the placeholder tokens defined in docs/src/plugins/remark-model-tokens/models.ts to match repo policy.
As per coding guidelines: “**/*.{ts,tsx,md,mdx,json}: When adding model names or IDs to examples, changesets, tests, or comments, use placeholder tokens from docs/src/plugins/remark-model-tokens/models.ts.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@packages/playground/src/domains/agent-builder/components/agent-list/__tests__/agent-builder-list.test.tsx`
around lines 188 - 276, The test fixtures in agent-builder-list.test.tsx use
hard-coded model objects (e.g., model: { provider: 'openai', name: 'gpt-4' })
inside the StoredAgentResponse fixtures passed to renderList; replace those
literal model provider/name strings with the corresponding placeholder tokens
exported from the repo's model tokens module (import the token constants and use
them for model.name and provider if available) so all test fixtures reference
the official placeholder tokens rather than hard-coded model names.
…ichment # Conflicts: # packages/server/src/server/handlers/stored-agents.ts
## What Unblocks CI for #17205 with two minimal, behavior-preserving fixes. ### 1. Lint — drop orphaned `resolveBuilderModelPolicy` import `packages/server/src/server/handlers/stored-agents.ts` imported `resolveBuilderModelPolicy` but had zero call sites. Save-path model-policy enforcement was intentionally removed on `main` (commit `a45fd541d1`); the merge from `main` into this branch left the import dangling. Comments at lines ~500 and ~664 already document the intentional removal of the check itself. ### 2. Test — use `getAllByText` for duplicated DOM nodes `packages/playground/src/pages/agent-builder/agents/__tests__/index.test.tsx` used `screen.getByText('Alice Doe')` and `getByText('bob@example.com')`. `AgentBuilderList` renders the `AuthorBadge` twice per row (once for mobile `md:hidden`, once for desktop `hidden md:flex`); jsdom doesn't apply CSS, so both nodes are queryable and `getByText` throws "multiple elements found". Switched to `getAllByText(...).length > 0`, matching the pattern already used in the colocated `agent-builder-list.test.tsx`. This is also what CodeRabbit flagged in its review. ## Verification - `pnpm --filter ./packages/server lint` — exit 0 - `pnpm --filter ./packages/server tsc --noEmit` — no errors - `pnpm --filter ./packages/server vitest run src/server/handlers/stored-agents.test.ts src/server/handlers/author-enrichment.test.ts` — 73 passed, 1 skipped (pre-existing) - `pnpm --filter ./packages/playground vitest run src/pages/agent-builder/agents/__tests__/index.test.tsx src/domains/agent-builder/components/agent-list/__tests__/agent-builder-list.test.tsx` — 18/18 pass (was 17/18) ## No changeset These are CI-fix-only edits with no user-visible behavior change. Co-authored-by: YJ <yj@example.com> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
) ## Summary Fixes a latent runtime crash in author enrichment for stored agents. `isUserProvider` (in `author-enrichment.ts`) only checked for `getCurrentUser`, but `prepareAuthorEnrichment` always calls `provider.getUser(...)` on the per-id fallback path. A provider that implements `getCurrentUser` but not `getUser` would pass the guard and then throw at runtime. This tightens the guard to also require `getUser`. Flagged by CodeRabbit during review of #17205. Targeting the feature branch so it lands inside #17205 before that merges to `main`. ## Changes - `author-enrichment.ts` — `isUserProvider` now also requires `getUser` to be a function - `author-enrichment.test.ts` — add case: provider with `getCurrentUser` but no `getUser` returns `null` ## Test plan - `pnpm --filter ./packages/server lint` — clean - `pnpm --filter ./packages/server tsc --noEmit` — no errors - `pnpm --filter ./packages/server vitest run src/server/handlers/author-enrichment.test.ts` — 15 passed - `pnpm --filter ./packages/server vitest run src/server/handlers/stored-agents.test.ts` — 59 passed, 1 skipped No changeset: behavior-preserving guard fix, no user-visible API change. Co-authored-by: YJ <yj@example.com> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai>
…ichment # Conflicts: # packages/playground/src/pages/agent-builder/agents/__tests__/index.test.tsx
…act rename The merge of main renamed @mastra/react's export from MastraDBMessage to MastraUIMessage, which broke the playground-ui build. The type is still exported by @mastra/core/agent/message-list, so import it from there to keep the existing Message types intact without depending on the removed re-export. Co-Authored-By: Mastra Code (anthropic/claude-opus-4-8) <noreply@mastra.ai>
The MastraDBMessage import from @mastra/core/agent/message-list must be ordered before @mastra/core/memory to satisfy the import/order lint rule, which was failing CI lint. Co-Authored-By: Mastra Code (anthropic/claude-opus-4-8) <noreply@mastra.ai>
What this ships
Today the agent-builder agent list shows each agent's avatar, name, description, and visibility — but not who authored it. The records carry an
authorId(resolved at write time from the caller's auth context), but the API never resolved that ID into a human-readable author. This PR closes that gap end-to-end.When an auth provider is configured, each row in the agent list (and the agent detail response) now includes a resolved
authorobject with the user's id, name, email, and avatar — and the playground renders it under the agent name.How it works
IUserProvidergains an optionalgetUsers(userIds)batch hook.CompositeAuthProviderandSimpleAuthProviderimplement it. Providers that don't override it still work via per-idgetUserfallback.author-enrichmenthelper mirrors the existing favorites-enrichment pattern: it dedupes author IDs on the page, calls the provider's batch method when available (otherwise fans outgetUserin parallel), and returns aMap<authorId, ResolvedAuthor>. The stored-agents list and get handlers attachauthorto each response record.storedAgentSchemaexposes an optionalauthor: { id, name?, email?, avatarUrl? }. The client SDK typeStoredAgentResponseis extended to match. The field is fully additive and optional everywhere, so existing clients keep working unchanged.lgso the row hierarchy reads cleanly with the new author block.Backwards compatibility
authoris optional at every layer (Zod, SDK type, UI). No existing test was modified.Test plan
composite-auth.test.ts; extendedsimple-auth.test.ts. Covers batch lookup ordering, provider fallthrough, throwing providers, unknown IDs.author-enrichment.test.ts(14 cases: batch vs per-id, dedup, null/empty/undefined IDs, provider throws, no auth provider, non-IUserProviderprovider,attachAuthorfield passthrough). New handler integration cases (list with enrichment, dedup verified via spy, favorited-only branch, no auth provider parity, get-by-id, per-id failure resilience).details()andlistStoredAgents().@mastra/client-js+ React Query stack againstGET /api/stored/agentsreturning fixtures withauthor.Local verification:
Manual smoke checks
/agent-builder/agentsand/agent-builder/library— author renders per row and on the detail page.ELI5
The server now looks up the human who created each stored agent and attaches a small author object (id plus optional name/email/avatar) to agent records when available, and the UI shows that as an author badge—if author info is missing nothing breaks.
Overview
Adds optional, end-to-end author enrichment for stored agents: stored-agent records retain authorId, the server can resolve those IDs into a public-safe ResolvedAuthor (id, optional name, email, avatarUrl) and attach it to list and detail responses, and the playground displays the resolved author. Enrichment is deduped, prefers batched provider lookups, falls back to per-id lookups, and degrades gracefully when no auth provider or resolution fails.
Key Changes
Core (packages/core)
Server (packages/server)
Client SDK (client-sdks/client-js)
Playground UI (packages/playground)
Technical Details
Testing
Comprehensive tests added across layers: