@dbx-tools/appkit-mastra 0.6.211 → 0.6.213

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/plugin.ts CHANGED
@@ -455,6 +455,16 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
455
455
  }
456
456
 
457
457
  override injectRoutes(router: IAppRouter): void {
458
+ this.registerMcpRoutes(router);
459
+ this.registerModelRoutes(router);
460
+ this.registerEmbedRoutes(router);
461
+ this.registerSuggestionRoutes(router);
462
+ this.registerFeedbackRoutes(router);
463
+ this.registerAgentRoutes(router);
464
+ }
465
+
466
+ /** Register URL aliases for Mastra's MCP transports. */
467
+ private registerMcpRoutes(router: IAppRouter): void {
458
468
  // Expose the MCP transport at the clean `/mcp` (plus the legacy
459
469
  // `/sse` + `/messages`) under the plugin mount. `@mastra/express`
460
470
  // mounts MCP under `/mcp/<serverId>/<transport>`, and the serverId
@@ -475,7 +485,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
475
485
  }
476
486
  next();
477
487
  });
488
+ }
478
489
 
490
+ /** Register model catalogue and per-agent default-model routes. */
491
+ private registerModelRoutes(router: IAppRouter): void {
479
492
  // `GET /models` exposes the cached endpoint list so clients can
480
493
  // populate model pickers, validate `?model=` choices, etc. Must
481
494
  // be registered before the catch-all that forwards everything to
@@ -537,7 +550,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
537
550
  path: `${routes.MASTRA_ROUTES.defaultModel}/:agentId`,
538
551
  handler: handleDefaultModel,
539
552
  });
553
+ }
540
554
 
555
+ /** Register the generic chart and statement embed resolver. */
556
+ private registerEmbedRoutes(router: IAppRouter): void {
541
557
  // `GET /embed/:type/:id` is the single resolver for every embed
542
558
  // marker the agent emits in prose (`[chart:<id>]`,
543
559
  // `[data:<id>]`, ...). `:type` selects a resolver from the
@@ -647,7 +663,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
647
663
  res.json(result.data);
648
664
  },
649
665
  });
666
+ }
650
667
 
668
+ /** Register default and agent-qualified suggestion routes. */
669
+ private registerSuggestionRoutes(router: IAppRouter): void {
651
670
  // `GET /suggestions` (and `/suggestions/:agentId`) returns the
652
671
  // curated starter questions for the agent's Genie space(s) - the
653
672
  // author-configured `sample_questions`, surfaced as one-tap
@@ -691,7 +710,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
691
710
  path: `${routes.MASTRA_ROUTES.suggestions}/:agentId`,
692
711
  handler: handleSuggestions,
693
712
  });
713
+ }
694
714
 
715
+ /** Register MLflow feedback submission when configured. */
716
+ private registerFeedbackRoutes(router: IAppRouter): void {
695
717
  // `POST /route/feedback` logs a thumbs / comment assessment against
696
718
  // a turn's MLflow trace (the `traceId` the client captured from the
697
719
  // stream response's trace-id header). Registered on the AppKit
@@ -735,7 +757,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
735
757
  });
736
758
  },
737
759
  });
760
+ }
738
761
 
762
+ /** Register the gated Mastra catch-all after every explicit route. */
763
+ private registerAgentRoutes(router: IAppRouter): void {
739
764
  // Middleware rather than `this.route`: this is the catch-all that hands
740
765
  // every remaining method / path pair to the Mastra sub-app, so it has no
741
766
  // single method or path to register under.
package/src/threads.ts CHANGED
@@ -21,7 +21,6 @@
21
21
  * @module
22
22
  */
23
23
 
24
- import { ValidationError } from "@databricks/appkit";
25
24
  import { log } from "@dbx-tools/shared-core";
26
25
  import {
27
26
  wire,
@@ -32,10 +31,14 @@ import {
32
31
  } from "@dbx-tools/shared-mastra";
33
32
  import type { Agent } from "@mastra/core/agent";
34
33
  import type { StorageThreadType } from "@mastra/core/memory";
35
- import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from "@mastra/core/request-context";
36
34
  import type { ContextWithMastra } from "@mastra/core/server";
37
35
  import { registerApiRoute } from "@mastra/core/server";
38
36
 
37
+ import {
38
+ resolveAgentRequestContext,
39
+ resolveAgentRouteOptions,
40
+ type AgentRouteOptions,
41
+ } from "./_agent-route-context.ts";
39
42
  import { clampPerPage, parseIntParam } from "./pagination.ts";
40
43
  import { invalidFields } from "./validation.ts";
41
44
 
@@ -196,8 +199,7 @@ export async function renameThread(opts: RenameThreadOptions): Promise<MastraThr
196
199
  }
197
200
 
198
201
  /** Options accepted by {@link threadsRoute}. */
199
- export type ThreadsRouteOptions =
200
- { path: `${string}:agentId${string}`; agent?: never } | { path: string; agent: string };
202
+ export type ThreadsRouteOptions = AgentRouteOptions;
201
203
 
202
204
  /**
203
205
  * Register the `<path>` Mastra custom API route. Handles three methods
@@ -221,45 +223,13 @@ export type ThreadsRouteOptions =
221
223
  * agent) and `/route/threads/:agentId`.
222
224
  */
223
225
  export function threadsRoute(options: ThreadsRouteOptions) {
224
- const { path } = options;
225
- const fixedAgent = "agent" in options ? options.agent : undefined;
226
- if (!fixedAgent && !path.includes(":agentId")) {
227
- throw ValidationError.invalidValue(
228
- "threadsRoute.path",
229
- path,
230
- "a path containing `:agentId`, or an explicit `agent`",
231
- );
232
- }
233
- // Shared by GET / DELETE: resolve the active agent and the caller's
234
- // resource id, returning a JSON error response when either is
235
- // missing. Keeps both handlers thin with identical validation.
236
- const resolveContext = (c: ContextWithMastra) => {
237
- const mastra = c.get("mastra");
238
- const requestContext = c.get("requestContext");
239
- const agentId = fixedAgent ?? c.req.param("agentId");
240
- if (!agentId) {
241
- return { error: c.json({ error: "agentId is required" }, 400) } as const;
242
- }
243
- const agent = mastra.getAgentById(agentId);
244
- if (!agent) {
245
- return {
246
- error: c.json({ error: `Unknown agent "${agentId}"` }, 404),
247
- } as const;
248
- }
249
- const resourceId = requestContext.get(MASTRA_RESOURCE_ID_KEY) as string | undefined;
250
- if (!resourceId) {
251
- return {
252
- error: c.json({ error: "resource id missing from request context" }, 400),
253
- } as const;
254
- }
255
- return { agentId, agent, requestContext, resourceId } as const;
256
- };
226
+ const { path, fixedAgent } = resolveAgentRouteOptions(options, "threadsRoute.path");
257
227
 
258
228
  return [
259
229
  registerApiRoute(path, {
260
230
  method: "GET",
261
231
  handler: async (c: ContextWithMastra) => {
262
- const ctx = resolveContext(c);
232
+ const ctx = resolveAgentRequestContext(c, { fixedAgent });
263
233
  if ("error" in ctx) return ctx.error;
264
234
  const payload = await listThreads({
265
235
  agent: ctx.agent,
@@ -273,21 +243,17 @@ export function threadsRoute(options: ThreadsRouteOptions) {
273
243
  registerApiRoute(path, {
274
244
  method: "DELETE",
275
245
  handler: async (c: ContextWithMastra) => {
276
- const ctx = resolveContext(c);
246
+ const ctx = resolveAgentRequestContext(c, { fixedAgent, threadId: "required" });
277
247
  if ("error" in ctx) return ctx.error;
278
- const threadId = ctx.requestContext.get(MASTRA_THREAD_ID_KEY) as string | undefined;
279
- if (!threadId) {
280
- return c.json({ error: "thread id missing from request context" }, 400);
281
- }
282
248
  const { deleted } = await deleteThread({
283
249
  agent: ctx.agent,
284
- threadId,
250
+ threadId: ctx.threadId,
285
251
  resourceId: ctx.resourceId,
286
252
  });
287
253
  const payload: MastraDeleteThreadResponse = {
288
254
  ok: true,
289
255
  agentId: ctx.agentId,
290
- threadId,
256
+ threadId: ctx.threadId,
291
257
  deleted,
292
258
  };
293
259
  return c.json(payload);
@@ -296,12 +262,8 @@ export function threadsRoute(options: ThreadsRouteOptions) {
296
262
  registerApiRoute(path, {
297
263
  method: "PATCH",
298
264
  handler: async (c: ContextWithMastra) => {
299
- const ctx = resolveContext(c);
265
+ const ctx = resolveAgentRequestContext(c, { fixedAgent, threadId: "required" });
300
266
  if ("error" in ctx) return ctx.error;
301
- const threadId = ctx.requestContext.get(MASTRA_THREAD_ID_KEY) as string | undefined;
302
- if (!threadId) {
303
- return c.json({ error: "thread id missing from request context" }, 400);
304
- }
305
267
  const body = wire.MastraUpdateThreadRequestSchema.safeParse(await c.req.json());
306
268
  if (!body.success) {
307
269
  logger.warn("rename:invalid", { error: body.error.message });
@@ -309,12 +271,12 @@ export function threadsRoute(options: ThreadsRouteOptions) {
309
271
  }
310
272
  const thread = await renameThread({
311
273
  agent: ctx.agent,
312
- threadId,
274
+ threadId: ctx.threadId,
313
275
  resourceId: ctx.resourceId,
314
276
  title: body.data.title,
315
277
  });
316
278
  if (!thread) {
317
- return c.json({ error: `Unknown thread "${threadId}"` }, 404);
279
+ return c.json({ error: `Unknown thread "${ctx.threadId}"` }, 404);
318
280
  }
319
281
  const payload: MastraUpdateThreadResponse = {
320
282
  ok: true,