Skip to content

Commit e17e5c1

Browse files
YujohnNattrassYJMastra Code (anthropic/claude-opus-4-7)abhiaiyer91
authored
feat(server,client-js): add stored agent dependents lookup endpoint (#17183)
## Summary This is PR 1 of 2 split from #17180. Adds a new server endpoint and client SDK method to look up agents that reference a given stored agent as a sub-agent. Used to warn before deleting or unsharing an agent that other agents depend on. ## Scope - New `GET /stored/agents/:storedAgentId/dependents` endpoint - Response splits dependents into two buckets: - `dependents` — caller-readable dependents (public agents and the caller's own private agents) with `id` + `name` - `hiddenCount` — cross-workspace dependents the caller cannot read, aggregated as a count and only surfaced when the target is public (avoids leaking cross-workspace structure) - Access mirrors `GET /stored/agents/:storedAgentId` (404 when caller cannot read target) - `client.getStoredAgent(id).dependents()` on the client-js SDK ```ts const { dependents, hiddenCount } = await client.getStoredAgent(id).dependents(); // { dependents: [{ id: 'parent-1', name: 'Triager' }], hiddenCount: 2 } ``` ## Intentionally excluded - The Studio UI warnings that consume this endpoint ship in the follow-up PR. ## Verification - Server tests pass (includes 10 dependents tests: static/conditional references, empty result, self-exclusion, prototype-key handling, 404 for missing/unreadable target, RBAC + `hiddenCount` semantics) - Server + client-js typecheck clean - `route-types.generated.ts` and CLI route metadata regenerated, permissions check passes - Editor overview docs updated with the new endpoint + SDK method <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## ELI5 This PR adds a way to check which other agents use a particular stored agent before you delete or unshare it — like seeing which LEGO builds use a brick before removing it. It provides a server endpoint and a client-js SDK method so callers can list readable dependents and learn how many unreadable (hidden) dependents exist. ## Overview Adds server and client-js support to list stored-agent dependents (used for delete/unshare warnings). Access control mirrors GET /stored/agents/:storedAgentId: callers get 404 if they cannot read the target. For public targets the response includes readable dependents and an aggregate hiddenCount for unreadable cross-workspace dependents; for non-public targets hidden dependents are not leaked. **New public API** - Server endpoint: GET /stored/agents/:storedAgentId/dependents - Client SDK method: client.getStoredAgent(id).dependents() ## Changes ### Server - New route handler: GET_STORED_AGENT_DEPENDENTS_ROUTE (packages/server/src/server/handlers/stored-agents.ts) - Scans published stored agents and detects references to the target via a new referencesTarget(subAgents, targetId) helper that supports both static object and array-of-conditional-variants snapshots. - Partitions results into caller-readable dependents (array of { id, name } — name defaults to id) and an aggregate hiddenCount for unreadable cross-workspace dependents. - Only populates hiddenCount when the target agent is public to avoid leaking cross-workspace structure. - Enforces read access (404 when caller cannot read target). - Wires response schema getStoredAgentDependentsResponseSchema. - Response schema: getStoredAgentDependentsResponseSchema added to packages/server/src/server/schemas/stored-agents.ts (dependents: {id,name}[], hiddenCount: nonnegative integer). - Route registration: Added to STORED_AGENTS_ROUTES before GET_STORED_AGENT_ROUTE to preserve literal-path matching precedence. - Tests: Comprehensive tests added in packages/server/src/server/handlers/stored-agents.test.ts covering static/conditional references, empty results, self-exclusion, ignoring prototype keys, 404 for missing/unreadable target, RBAC, and hiddenCount semantics. Mocks updated (MockStoredAgent.agents widened; listResolved perPage supports number | false). ### Client-js SDK & Types - client-sdks/client-js/src/resources/stored-agent.ts: StoredAgent.dependents(requestContext?) -> Promise<StoredAgentDependentsResponse>. - client-sdks/client-js/src/types.ts: Added StoredAgentDependent { id, name } and StoredAgentDependentsResponse { dependents, hiddenCount }. - client-sdks/client-js/src/route-types.generated.ts: Generated route/type definitions for the new endpoint. ### Tooling, Metadata & Docs - CLI route metadata regenerated: packages/cli/src/commands/api/route-metadata.generated.ts updated with the new route entry. - docs/src/content/en/docs/editor/overview.mdx: Documentation updated to mention the new endpoint and SDK helper and explain dependents and hiddenCount. - Changeset: .changeset/agent-delete-dependents-warning.md marks `@mastra/server` and `@mastra/client-js` as minor releases. ## Verification - Server tests pass (10 dependents tests covering the behaviors above). - Server and client-js typecheck clean. - route-types.generated.ts and CLI route metadata regenerated; permissions check passes. - Studio UI warning integration excluded from this PR (will be shipped in a follow-up). ## Commit - Single commit: "chore: harden prototype-key test, document dependents endpoint" <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: YJ <yj@example.com> Co-authored-by: Mastra Code (anthropic/claude-opus-4-7) <noreply@mastra.ai> Co-authored-by: Abhi Aiyer <abhiaiyer91@gmail.com>
1 parent c973db4 commit e17e5c1

10 files changed

Lines changed: 454 additions & 7 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@mastra/server': minor
3+
'@mastra/client-js': minor
4+
---
5+
6+
Added `GET /stored/agents/:storedAgentId/dependents` endpoint that lists agents
7+
referencing a stored agent as a sub-agent.
8+
9+
```ts
10+
const { dependents, hiddenCount } = await client.getStoredAgent(id).dependents();
11+
// { dependents: [{ id: 'parent-1', name: 'Triager' }], hiddenCount: 2 }
12+
```
13+
14+
- `dependents` — caller-readable agents (public agents and the caller's own private
15+
agents) with `id` + `name`.
16+
- `hiddenCount` — cross-workspace dependents the caller cannot read, only surfaced
17+
when the target agent is public.
18+
19+
Access mirrors `GET /stored/agents/:storedAgentId` — 404 when the caller cannot
20+
read the target.

client-sdks/client-js/src/resources/stored-agent.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
StoredAgentResponse,
66
UpdateStoredAgentParams,
77
DeleteStoredAgentResponse,
8+
StoredAgentDependentsResponse,
89
AgentVersionResponse,
910
ListAgentVersionsParams,
1011
ListAgentVersionsResponse,
@@ -90,6 +91,18 @@ export class StoredAgent extends BaseResource {
9091
);
9192
}
9293

94+
/**
95+
* Lists other stored agents that reference this agent as a sub-agent.
96+
* @param requestContext - Optional request context to pass as query parameter
97+
* @returns Promise containing the list of dependent agents and a hidden count
98+
* for cross-workspace private dependents (only non-zero when this agent is public).
99+
*/
100+
dependents(requestContext?: RequestContext | Record<string, any>): Promise<StoredAgentDependentsResponse> {
101+
return this.request(
102+
`/stored/agents/${encodeURIComponent(this.storedAgentId)}/dependents${requestContextQueryString(requestContext)}`,
103+
);
104+
}
105+
93106
// ==========================================================================
94107
// Favorite Methods (EE feature)
95108
// ==========================================================================

client-sdks/client-js/src/route-types.generated.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25649,6 +25649,39 @@ export interface PostStoredAgentsPreviewInstructions_RouteContract {
2564925649
responseType: 'json';
2565025650
}
2565125651

25652+
// ============================================================================
25653+
// Route: GET /stored/agents/:storedAgentId/dependents
25654+
// ============================================================================
25655+
export type GetStoredAgentsStoredAgentIdDependents_PathParams = {
25656+
/** Unique identifier for the stored agent */
25657+
storedAgentId: string;
25658+
};
25659+
25660+
export type GetStoredAgentsStoredAgentIdDependents_Response = {
25661+
dependents: {
25662+
id: string;
25663+
name: string;
25664+
}[];
25665+
hiddenCount: number;
25666+
};
25667+
25668+
export type GetStoredAgentsStoredAgentIdDependents_Request = Simplify<
25669+
(GetStoredAgentsStoredAgentIdDependents_PathParams extends never
25670+
? {}
25671+
: { params: GetStoredAgentsStoredAgentIdDependents_PathParams }) &
25672+
(never extends never ? {} : {} extends never ? { query?: never } : { query: never }) &
25673+
(never extends never ? {} : {} extends never ? { body?: never } : { body: never })
25674+
>;
25675+
25676+
export interface GetStoredAgentsStoredAgentIdDependents_RouteContract {
25677+
pathParams: GetStoredAgentsStoredAgentIdDependents_PathParams;
25678+
queryParams: never;
25679+
body: never;
25680+
request: GetStoredAgentsStoredAgentIdDependents_Request;
25681+
response: GetStoredAgentsStoredAgentIdDependents_Response;
25682+
responseType: 'json';
25683+
}
25684+
2565225685
// ============================================================================
2565325686
// Route: POST /stored/agents/:storedAgentId/export
2565425687
// ============================================================================
@@ -84990,6 +85023,7 @@ export interface RouteTypes {
8499085023
'POST /mcp/:serverId/messages': PostMcpServerIdMessages_RouteContract;
8499185024
'GET /stored/agents': GetStoredAgents_RouteContract;
8499285025
'POST /stored/agents/preview-instructions': PostStoredAgentsPreviewInstructions_RouteContract;
85026+
'GET /stored/agents/:storedAgentId/dependents': GetStoredAgentsStoredAgentIdDependents_RouteContract;
8499385027
'POST /stored/agents/:storedAgentId/export': PostStoredAgentsStoredAgentIdExport_RouteContract;
8499485028
'GET /stored/agents/:storedAgentId': GetStoredAgentsStoredAgentId_RouteContract;
8499585029
'POST /stored/agents': PostStoredAgents_RouteContract;
@@ -85745,6 +85779,9 @@ export interface Client {
8574585779
GET: GetStoredAgentsStoredAgentId_RouteContract;
8574685780
PATCH: PatchStoredAgentsStoredAgentId_RouteContract;
8574785781
};
85782+
'/stored/agents/:storedAgentId/dependents': {
85783+
GET: GetStoredAgentsStoredAgentIdDependents_RouteContract;
85784+
};
8574885785
'/stored/agents/:storedAgentId/export': {
8574985786
POST: PostStoredAgentsStoredAgentIdExport_RouteContract;
8575085787
};

client-sdks/client-js/src/types.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,6 +1441,26 @@ export interface DeleteStoredAgentResponse {
14411441
message: string;
14421442
}
14431443

1444+
/**
1445+
* A single agent that references another agent as a sub-agent. Includes both
1446+
* public and the caller's own private agents — anything the caller can read.
1447+
*/
1448+
export interface StoredAgentDependent {
1449+
id: string;
1450+
name: string;
1451+
}
1452+
1453+
/**
1454+
* Response for listing dependents of a stored agent.
1455+
* `dependents` lists caller-readable references (with names).
1456+
* `hiddenCount` aggregates dependents the caller cannot read; it is only
1457+
* non-zero when the target agent is public.
1458+
*/
1459+
export interface StoredAgentDependentsResponse {
1460+
dependents: StoredAgentDependent[];
1461+
hiddenCount: number;
1462+
}
1463+
14441464
// ============================================================================
14451465
// Stored Scorer Definition Types
14461466
// ============================================================================

docs/src/content/en/docs/editor/overview.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,10 @@ The same operations are available over HTTP through the Mastra server. Use these
153153
| `GET` | `/stored/agents/:storedAgentId` | Get a stored agent by ID. |
154154
| `PATCH` | `/stored/agents/:storedAgentId` | Update a stored agent. |
155155
| `DELETE` | `/stored/agents/:storedAgentId` | Delete a stored agent. |
156+
| `GET` | `/stored/agents/:storedAgentId/dependents` | List agents that reference this agent as a sub-agent. |
156157
| `POST` | `/stored/agents/:storedAgentId/export` | Export a stored agent's override as a deterministic JSON config. |
157158

158-
The export endpoint returns only the fields the agent's [`editor` config](/reference/agents/agent#editor-overrides) allows, so the output matches the per-agent file the code source writes to disk. The Client SDK wraps these endpoints with `client.listStoredAgents()`, `client.createStoredAgent()`, `client.getStoredAgent()`, and `client.getStoredAgent(id).export()`. Version management endpoints live under `/stored/agents/:storedAgentId/versions`, see [version management](/reference/client-js/agents#version-management) for the full list.
159+
The dependents endpoint helps warn before deleting or unsharing an agent that other agents depend on: `dependents` lists caller-readable agents by `id` and `name`, while `hiddenCount` aggregates cross-workspace references the caller cannot read (surfaced only when the target is public). The export endpoint returns only the fields the agent's [`editor` config](/reference/agents/agent#editor-overrides) allows, so the output matches the per-agent file the code source writes to disk. The Client SDK wraps these endpoints with `client.listStoredAgents()`, `client.createStoredAgent()`, `client.getStoredAgent()`, `client.getStoredAgent(id).dependents()`, and `client.getStoredAgent(id).export()`. Version management endpoints live under `/stored/agents/:storedAgentId/versions`, see [version management](/reference/client-js/agents#version-management) for the full list.
159160

160161
### Automated experimentation
161162

packages/cli/src/commands/api/route-metadata.generated.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,6 +3228,21 @@ export const API_ROUTE_METADATA = {
32283228
"kind": "single"
32293229
}
32303230
},
3231+
"GET /stored/agents/:storedAgentId/dependents": {
3232+
"method": "GET",
3233+
"path": "/stored/agents/:storedAgentId/dependents",
3234+
"pathParams": [
3235+
"storedAgentId"
3236+
],
3237+
"queryParams": [],
3238+
"bodyParams": [],
3239+
"hasQuery": false,
3240+
"hasBody": false,
3241+
"responseShape": {
3242+
"kind": "object-property",
3243+
"listProperty": "dependents"
3244+
}
3245+
},
32313246
"POST /stored/agents/:storedAgentId/export": {
32323247
"method": "POST",
32333248
"path": "/stored/agents/:storedAgentId/export",

0 commit comments

Comments
 (0)