@dbx-tools/appkit-mastra 0.1.42 → 0.1.56

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/index.ts CHANGED
@@ -25,4 +25,3 @@ export {
25
25
  extractModelOverride,
26
26
  type ModelOverrideRequest,
27
27
  } from "./src/serving.js";
28
- export * from "./src/tools/email.js";
package/package.json CHANGED
@@ -9,14 +9,14 @@
9
9
  }
10
10
  },
11
11
  "name": "@dbx-tools/appkit-mastra",
12
- "version": "0.1.42",
12
+ "version": "0.1.56",
13
13
  "dependencies": {
14
14
  "@databricks/sdk-experimental": "^0.17",
15
- "@dbx-tools/appkit-mastra-shared": "0.1.42",
16
- "@dbx-tools/genie": "0.1.42",
17
- "@dbx-tools/genie-shared": "0.1.42",
18
- "@dbx-tools/model": "0.1.42",
19
- "@dbx-tools/shared": "0.1.42",
15
+ "@dbx-tools/appkit-mastra-shared": "0.1.56",
16
+ "@dbx-tools/genie": "0.1.56",
17
+ "@dbx-tools/genie-shared": "0.1.56",
18
+ "@dbx-tools/model": "0.1.56",
19
+ "@dbx-tools/shared": "0.1.56",
20
20
  "@mastra/ai-sdk": "^1",
21
21
  "@mastra/core": "^1",
22
22
  "@mastra/express": "^1",
@@ -28,11 +28,6 @@
28
28
  "pg": "^8.20.0",
29
29
  "zod": "^4.3.6"
30
30
  },
31
- "devDependencies": {
32
- "@types/express": "^5",
33
- "@types/pg": "^8",
34
- "express": "^5"
35
- },
36
31
  "module": "index.ts",
37
32
  "peerDependencies": {
38
33
  "@databricks/appkit": "^0.41",
package/src/chart.ts CHANGED
@@ -39,7 +39,7 @@ import { createTool } from "@mastra/core/tools";
39
39
  import { z } from "zod";
40
40
 
41
41
  import type { MastraPluginConfig } from "./config.js";
42
- import { buildModel, ModelTier } from "./model.js";
42
+ import { buildModel, ModelClass } from "./model.js";
43
43
 
44
44
  const log = logUtils.logger("mastra/chart");
45
45
 
@@ -330,7 +330,7 @@ function getPlannerAgent(config: MastraPluginConfig): Agent {
330
330
  description: "Picks chart type and axis encodings for a dataset.",
331
331
  instructions: CHART_PLANNER_INSTRUCTIONS,
332
332
  model: ({ requestContext }) =>
333
- buildModel(config, requestContext, { tier: ModelTier.Fast }),
333
+ buildModel(config, requestContext, { modelClass: ModelClass.ChatFast }),
334
334
  });
335
335
  plannerAgents.set(config, agent);
336
336
  }
package/src/config.ts CHANGED
@@ -5,7 +5,8 @@
5
5
  * `memory.ts` can import them without creating a cycle.
6
6
  */
7
7
 
8
- import type { BasePluginConfig, getExecutionContext } from "@databricks/appkit";
8
+ import type { BasePluginConfig } from "@databricks/appkit";
9
+ import type { appkitUtils } from "@dbx-tools/shared";
9
10
  import type { AgentConfig } from "@mastra/core/agent";
10
11
  import {
11
12
  MASTRA_RESOURCE_ID_KEY,
@@ -71,7 +72,7 @@ export const TRACE_REQUEST_CONTEXT_KEYS: readonly string[] = [
71
72
  /** AppKit execution context plus the canonical user id. */
72
73
  export interface User {
73
74
  id: string;
74
- executionContext: ReturnType<typeof getExecutionContext>;
75
+ executionContext: appkitUtils.ExecutionContextLike;
75
76
  }
76
77
 
77
78
  /** PgVector config with an optional Mastra store id. */
@@ -207,9 +208,10 @@ export interface MastraPluginConfig extends BasePluginConfig {
207
208
  *
208
209
  * When unset, resolution is driven by the live Foundation Model API
209
210
  * `quality` / `speed` / `cost` scores: endpoints are classified into
210
- * tiers (`classifyEndpoints`) and walked best-first (Thinking ->
211
- * Balanced -> Fast), with the small built-in `FALLBACK_MODEL_IDS`
212
- * list as the floor when the catalogue can't be read. Set this to
211
+ * chat classes (`classifyEndpoints`) and walked best-first
212
+ * (ChatThinking -> ChatBalanced -> ChatFast), with the small built-in
213
+ * `FALLBACK_MODEL_IDS` list as the floor when the catalogue can't be
214
+ * read. Set this to
213
215
  * pin a regulated workspace to an approved subset, or to put custom
214
216
  * endpoints in front of the auto-classified catalogue.
215
217
  */
package/src/model.ts CHANGED
@@ -9,19 +9,19 @@
9
9
  *
10
10
  * This module only adds the Mastra-specific glue. The actual model
11
11
  * selection - listing the workspace catalogue and resolving an
12
- * explicit name / tier / fallback chain to a real endpoint id - lives
12
+ * explicit name / class / fallback chain to a real endpoint id - lives
13
13
  * in `@dbx-tools/model` ({@link selectModel}) so non-Mastra consumers
14
14
  * (e.g. a job that just needs a model name) can reuse it. Here we
15
15
  * assemble the explicit ask from Mastra's request context (the
16
16
  * per-request override under {@link MASTRA_MODEL_OVERRIDE_KEY}, the
17
17
  * agent / plugin `modelId`, or `DATABRICKS_SERVING_ENDPOINT_NAME`),
18
- * pass the plugin's fuzzy / tier / fallback knobs through, and wrap
18
+ * pass the plugin's fuzzy / class / fallback knobs through, and wrap
19
19
  * the resolved id in the OpenAI-compatible provider config Mastra
20
20
  * expects. Catalogue fetches fail loud: network / auth errors
21
21
  * propagate so callers see the real SDK message.
22
22
  */
23
23
 
24
- import { type ModelTier, parseModelTier, selectModel } from "@dbx-tools/model";
24
+ import { type ModelClass, parseModelClass, selectModel } from "@dbx-tools/model";
25
25
  import { commonUtils, logUtils, netUtils, stringUtils } from "@dbx-tools/shared";
26
26
  import type { MastraModelConfig } from "@mastra/core/llm";
27
27
  import type { RequestContext } from "@mastra/core/request-context";
@@ -32,9 +32,9 @@ import { MASTRA_MODEL_OVERRIDE_KEY, resolveServingConfig } from "./serving.js";
32
32
  export {
33
33
  classifyEndpoints,
34
34
  FALLBACK_MODEL_IDS,
35
- modelForTier,
36
- modelsForTier,
37
- ModelTier,
35
+ ModelClass,
36
+ modelForClass,
37
+ modelsForClass,
38
38
  } from "@dbx-tools/model";
39
39
 
40
40
  /** Optional overrides accepted by {@link buildModel}. */
@@ -42,18 +42,18 @@ export interface BuildModelOverrides {
42
42
  /**
43
43
  * Static model id from the agent / plugin config (string sugar on
44
44
  * `def.model` or `config.defaultModel`). Loses to the per-request
45
- * override but wins over env / tier / fallback.
45
+ * override but wins over env / class / fallback.
46
46
  */
47
47
  modelId?: string;
48
48
  /**
49
- * Capability tier to resolve when no explicit model id is supplied.
50
- * Used by internal agents (e.g. the chart planner asks for
51
- * {@link ModelTier.Fast}) to express intent without pinning an
49
+ * Chat capability class to resolve when no explicit model id is
50
+ * supplied. Used by internal agents (e.g. the chart planner asks for
51
+ * {@link ModelClass.ChatFast}) to express intent without pinning an
52
52
  * endpoint name; the live catalogue is classified and the top
53
- * available model in the tier is chosen, falling back to the
54
- * tier's static list when the workspace has none.
53
+ * available model in the class is chosen, falling back to the
54
+ * class's static list when the workspace has none.
55
55
  */
56
- tier?: ModelTier;
56
+ modelClass?: ModelClass;
57
57
  }
58
58
 
59
59
  /**
@@ -85,23 +85,23 @@ export async function buildModel(
85
85
  : undefined;
86
86
 
87
87
  // The override / agent default / env value can be either a concrete
88
- // endpoint name or a capability tier slug ("thinking" / "balanced" /
89
- // "fast"). A tier slug becomes a tier intent (let the live catalogue
90
- // pick the best model in that band); anything else is an explicit
91
- // name fuzzy-matched against the catalogue. An internal
92
- // `overrides.tier` (e.g. the chart planner) is the floor when nothing
93
- // was requested.
88
+ // endpoint name or a model class slug ("chat-thinking" /
89
+ // "chat-balanced" / "chat-fast"). A class slug becomes a class intent
90
+ // (let the live catalogue pick the best model in that band); anything
91
+ // else is an explicit name fuzzy-matched against the catalogue. An
92
+ // internal `overrides.modelClass` (e.g. the chart planner) is the
93
+ // floor when nothing was requested.
94
94
  const requested =
95
95
  override ?? overrides.modelId ?? process.env.DATABRICKS_SERVING_ENDPOINT_NAME;
96
- const requestedTier = requested !== undefined ? parseModelTier(requested) : null;
97
- const explicit = requestedTier === null ? requested : undefined;
98
- const tier = requestedTier ?? overrides.tier;
96
+ const requestedClass = requested !== undefined ? parseModelClass(requested) : null;
97
+ const explicit = requestedClass === null ? requested : undefined;
98
+ const modelClass = requestedClass ?? overrides.modelClass;
99
99
 
100
100
  const { modelId, source } = await selectModel(user.executionContext.client, host, {
101
101
  ...(explicit !== undefined ? { explicit } : {}),
102
102
  fuzzy: serving.fuzzy,
103
103
  threshold: serving.threshold,
104
- ...(tier !== undefined ? { tier } : {}),
104
+ ...(modelClass !== undefined ? { modelClass } : {}),
105
105
  fallbacks: serving.fallbacks,
106
106
  ttlMs: serving.ttlMs,
107
107
  });
package/src/serving.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Mastra-specific glue over the generic `@dbx-tools/model` toolkit.
3
3
  *
4
4
  * The live `/serving-endpoints` catalogue access, fuzzy name
5
- * resolution, and tier/fallback selection all live in
5
+ * resolution, and class/fallback selection all live in
6
6
  * `@dbx-tools/model`; this module only adds what is specific to the
7
7
  * Mastra plugin: pulling a per-request model override off an HTTP
8
8
  * request (header / query / body) and projecting the plugin config
@@ -1,83 +0,0 @@
1
- /**
2
- * Mastra tool: `send_email`. Gated behind {@link requireApproval}
3
- * so the model can call it freely but execution is paused until a
4
- * human approves via the chat UI.
5
- *
6
- * The execute body is a stub - it logs the would-be email to the
7
- * server console (via `logUtils.logger`) and returns success. Swap
8
- * in a real SMTP / SES / Resend / Workspace Mail call later by
9
- * editing the `execute` body; the tool surface and approval gate
10
- * stay the same.
11
- *
12
- * Approval flow (Mastra + AI SDK V5):
13
- *
14
- * 1. Model calls the tool with `{ to, subject, body, ... }`.
15
- * 2. Mastra evaluates `requireApproval` (here always `true`),
16
- * pauses the agent loop, and emits a `tool-call-approval`
17
- * chunk on the response stream.
18
- * 3. The chat client renders an approve/deny prompt against the
19
- * `state: 'approval-requested'` tool part. On approve, it sends
20
- * a `MastraToolApproval` response back; on deny, the tool call
21
- * is rejected and the model sees an error.
22
- * 4. On approve, this `execute` runs and logs the email.
23
- *
24
- * The tool is intentionally NOT auto-installed on every agent -
25
- * email is domain-specific, not infrastructure. Spread it into the
26
- * specific agents that should be able to draft emails.
27
- */
28
- import { z } from "zod";
29
- declare const emailInputSchema: z.ZodObject<{
30
- to: z.ZodString;
31
- subject: z.ZodString;
32
- body: z.ZodString;
33
- cc: z.ZodOptional<z.ZodArray<z.ZodString>>;
34
- bcc: z.ZodOptional<z.ZodArray<z.ZodString>>;
35
- }, z.core.$strip>;
36
- /** Options accepted by {@link buildEmailTool}. */
37
- export interface BuildEmailToolOptions {
38
- /**
39
- * Override the tool id. Defaults to `"send_email"`. Useful if a
40
- * caller wants `send_internal_email` / `send_external_email`
41
- * variants.
42
- */
43
- id?: string;
44
- /**
45
- * Replace the default execute body with a real provider call.
46
- * Receives the validated input and must return `{sent, recipient}`.
47
- * The console-log default is meant for demos / dev; production
48
- * deployments should wire SMTP / SES / Resend / Workspace Mail
49
- * here.
50
- */
51
- send?: (input: z.infer<typeof emailInputSchema>) => Promise<void> | void;
52
- }
53
- /**
54
- * Build the `send_email` tool. Approval-gated by default; the
55
- * execute body either calls the supplied {@link send} hook or
56
- * logs the email to the server console as a demo stub.
57
- *
58
- * @example
59
- * ```ts
60
- * import { buildEmailTool, createAgent, mastra } from "@dbx-tools/appkit-mastra";
61
- *
62
- * const support = createAgent({
63
- * instructions: "...",
64
- * tools(plugins) {
65
- * return {
66
- * ...(plugins.genie?.toolkit() ?? {}),
67
- * send_email: buildEmailTool(),
68
- * };
69
- * },
70
- * });
71
- * ```
72
- */
73
- export declare function buildEmailTool(opts?: BuildEmailToolOptions): import("@mastra/core/tools").Tool<{
74
- to: string;
75
- subject: string;
76
- body: string;
77
- cc?: string[] | undefined;
78
- bcc?: string[] | undefined;
79
- }, {
80
- sent: boolean;
81
- recipient: string;
82
- }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, string, unknown>;
83
- export {};
@@ -1,121 +0,0 @@
1
- /**
2
- * Mastra tool: `send_email`. Gated behind {@link requireApproval}
3
- * so the model can call it freely but execution is paused until a
4
- * human approves via the chat UI.
5
- *
6
- * The execute body is a stub - it logs the would-be email to the
7
- * server console (via `logUtils.logger`) and returns success. Swap
8
- * in a real SMTP / SES / Resend / Workspace Mail call later by
9
- * editing the `execute` body; the tool surface and approval gate
10
- * stay the same.
11
- *
12
- * Approval flow (Mastra + AI SDK V5):
13
- *
14
- * 1. Model calls the tool with `{ to, subject, body, ... }`.
15
- * 2. Mastra evaluates `requireApproval` (here always `true`),
16
- * pauses the agent loop, and emits a `tool-call-approval`
17
- * chunk on the response stream.
18
- * 3. The chat client renders an approve/deny prompt against the
19
- * `state: 'approval-requested'` tool part. On approve, it sends
20
- * a `MastraToolApproval` response back; on deny, the tool call
21
- * is rejected and the model sees an error.
22
- * 4. On approve, this `execute` runs and logs the email.
23
- *
24
- * The tool is intentionally NOT auto-installed on every agent -
25
- * email is domain-specific, not infrastructure. Spread it into the
26
- * specific agents that should be able to draft emails.
27
- */
28
- import { logUtils, stringUtils } from "@dbx-tools/shared";
29
- import { createTool } from "@mastra/core/tools";
30
- import { z } from "zod";
31
- const log = logUtils.logger("mastra/tool/send-email");
32
- const emailInputSchema = z.object({
33
- to: z.string().describe(stringUtils.toDescription(`
34
- Single recipient email address (e.g. "alice@example.com"). For
35
- multiple recipients, comma-separate them yourself.
36
- `)),
37
- subject: z.string().describe(stringUtils.toDescription(`
38
- Subject line.
39
- `)),
40
- body: z.string().describe(stringUtils.toDescription(`
41
- Email body. Plain text or markdown; the renderer downstream decides
42
- which to honour. Be specific - the recipient may not have any
43
- context the model has from prior chat turns.
44
- `)),
45
- cc: z
46
- .array(z.string())
47
- .optional()
48
- .describe(stringUtils.toDescription(`
49
- Optional CC recipients.
50
- `)),
51
- bcc: z
52
- .array(z.string())
53
- .optional()
54
- .describe(stringUtils.toDescription(`
55
- Optional BCC recipients.
56
- `)),
57
- });
58
- const emailOutputSchema = z.object({
59
- sent: z.boolean().describe(stringUtils.toDescription(`
60
- True when the email was dispatched. The current implementation
61
- always returns true after console-logging the would-be email; swap
62
- in a real provider to make this meaningful.
63
- `)),
64
- recipient: z.string().describe(stringUtils.toDescription(`
65
- Echo of the \`to\` field for confirmation.
66
- `)),
67
- });
68
- /**
69
- * Build the `send_email` tool. Approval-gated by default; the
70
- * execute body either calls the supplied {@link send} hook or
71
- * logs the email to the server console as a demo stub.
72
- *
73
- * @example
74
- * ```ts
75
- * import { buildEmailTool, createAgent, mastra } from "@dbx-tools/appkit-mastra";
76
- *
77
- * const support = createAgent({
78
- * instructions: "...",
79
- * tools(plugins) {
80
- * return {
81
- * ...(plugins.genie?.toolkit() ?? {}),
82
- * send_email: buildEmailTool(),
83
- * };
84
- * },
85
- * });
86
- * ```
87
- */
88
- export function buildEmailTool(opts = {}) {
89
- return createTool({
90
- id: opts.id ?? "send_email",
91
- description: stringUtils.toDescription(`
92
- Send an email on the user's behalf. Pass a recipient address,
93
- subject, and body; the user will be prompted to approve the send
94
- before it goes out (the tool is approval-gated). Use this when
95
- the user explicitly asks to send / forward / share something via
96
- email - never autonomously. Keep subjects short and bodies
97
- focused; the recipient may not have any of the chat context.
98
- `),
99
- inputSchema: emailInputSchema,
100
- outputSchema: emailOutputSchema,
101
- requireApproval: true,
102
- execute: async (input) => {
103
- const { to, subject, body, cc, bcc } = input;
104
- // Default behaviour: dump the email to the server console so
105
- // demos can see the gate fire end-to-end without a real
106
- // provider. Replace by passing `opts.send`.
107
- log.info("send", {
108
- to,
109
- ...(cc && cc.length > 0 ? { cc } : {}),
110
- ...(bcc && bcc.length > 0 ? { bcc } : {}),
111
- subject,
112
- bodyLength: body.length,
113
- body,
114
- });
115
- if (opts.send) {
116
- await opts.send(input);
117
- }
118
- return { sent: true, recipient: to };
119
- },
120
- });
121
- }
@@ -1,158 +0,0 @@
1
- /**
2
- * Mastra tool: `send_email`. Gated behind {@link requireApproval}
3
- * so the model can call it freely but execution is paused until a
4
- * human approves via the chat UI.
5
- *
6
- * The execute body is a stub - it logs the would-be email to the
7
- * server console (via `logUtils.logger`) and returns success. Swap
8
- * in a real SMTP / SES / Resend / Workspace Mail call later by
9
- * editing the `execute` body; the tool surface and approval gate
10
- * stay the same.
11
- *
12
- * Approval flow (Mastra + AI SDK V5):
13
- *
14
- * 1. Model calls the tool with `{ to, subject, body, ... }`.
15
- * 2. Mastra evaluates `requireApproval` (here always `true`),
16
- * pauses the agent loop, and emits a `tool-call-approval`
17
- * chunk on the response stream.
18
- * 3. The chat client renders an approve/deny prompt against the
19
- * `state: 'approval-requested'` tool part. On approve, it sends
20
- * a `MastraToolApproval` response back; on deny, the tool call
21
- * is rejected and the model sees an error.
22
- * 4. On approve, this `execute` runs and logs the email.
23
- *
24
- * The tool is intentionally NOT auto-installed on every agent -
25
- * email is domain-specific, not infrastructure. Spread it into the
26
- * specific agents that should be able to draft emails.
27
- */
28
-
29
- import { logUtils, stringUtils } from "@dbx-tools/shared";
30
- import { createTool } from "@mastra/core/tools";
31
- import { z } from "zod";
32
-
33
- const log = logUtils.logger("mastra/tool/send-email");
34
-
35
- const emailInputSchema = z.object({
36
- to: z.string().describe(
37
- stringUtils.toDescription(`
38
- Single recipient email address (e.g. "alice@example.com"). For
39
- multiple recipients, comma-separate them yourself.
40
- `),
41
- ),
42
- subject: z.string().describe(
43
- stringUtils.toDescription(`
44
- Subject line.
45
- `),
46
- ),
47
- body: z.string().describe(
48
- stringUtils.toDescription(`
49
- Email body. Plain text or markdown; the renderer downstream decides
50
- which to honour. Be specific - the recipient may not have any
51
- context the model has from prior chat turns.
52
- `),
53
- ),
54
- cc: z
55
- .array(z.string())
56
- .optional()
57
- .describe(
58
- stringUtils.toDescription(`
59
- Optional CC recipients.
60
- `),
61
- ),
62
- bcc: z
63
- .array(z.string())
64
- .optional()
65
- .describe(
66
- stringUtils.toDescription(`
67
- Optional BCC recipients.
68
- `),
69
- ),
70
- });
71
-
72
- const emailOutputSchema = z.object({
73
- sent: z.boolean().describe(
74
- stringUtils.toDescription(`
75
- True when the email was dispatched. The current implementation
76
- always returns true after console-logging the would-be email; swap
77
- in a real provider to make this meaningful.
78
- `),
79
- ),
80
- recipient: z.string().describe(
81
- stringUtils.toDescription(`
82
- Echo of the \`to\` field for confirmation.
83
- `),
84
- ),
85
- });
86
-
87
- /** Options accepted by {@link buildEmailTool}. */
88
- export interface BuildEmailToolOptions {
89
- /**
90
- * Override the tool id. Defaults to `"send_email"`. Useful if a
91
- * caller wants `send_internal_email` / `send_external_email`
92
- * variants.
93
- */
94
- id?: string;
95
- /**
96
- * Replace the default execute body with a real provider call.
97
- * Receives the validated input and must return `{sent, recipient}`.
98
- * The console-log default is meant for demos / dev; production
99
- * deployments should wire SMTP / SES / Resend / Workspace Mail
100
- * here.
101
- */
102
- send?: (input: z.infer<typeof emailInputSchema>) => Promise<void> | void;
103
- }
104
-
105
- /**
106
- * Build the `send_email` tool. Approval-gated by default; the
107
- * execute body either calls the supplied {@link send} hook or
108
- * logs the email to the server console as a demo stub.
109
- *
110
- * @example
111
- * ```ts
112
- * import { buildEmailTool, createAgent, mastra } from "@dbx-tools/appkit-mastra";
113
- *
114
- * const support = createAgent({
115
- * instructions: "...",
116
- * tools(plugins) {
117
- * return {
118
- * ...(plugins.genie?.toolkit() ?? {}),
119
- * send_email: buildEmailTool(),
120
- * };
121
- * },
122
- * });
123
- * ```
124
- */
125
- export function buildEmailTool(opts: BuildEmailToolOptions = {}) {
126
- return createTool({
127
- id: opts.id ?? "send_email",
128
- description: stringUtils.toDescription(`
129
- Send an email on the user's behalf. Pass a recipient address,
130
- subject, and body; the user will be prompted to approve the send
131
- before it goes out (the tool is approval-gated). Use this when
132
- the user explicitly asks to send / forward / share something via
133
- email - never autonomously. Keep subjects short and bodies
134
- focused; the recipient may not have any of the chat context.
135
- `),
136
- inputSchema: emailInputSchema,
137
- outputSchema: emailOutputSchema,
138
- requireApproval: true,
139
- execute: async (input) => {
140
- const { to, subject, body, cc, bcc } = input as z.infer<typeof emailInputSchema>;
141
- // Default behaviour: dump the email to the server console so
142
- // demos can see the gate fire end-to-end without a real
143
- // provider. Replace by passing `opts.send`.
144
- log.info("send", {
145
- to,
146
- ...(cc && cc.length > 0 ? { cc } : {}),
147
- ...(bcc && bcc.length > 0 ? { bcc } : {}),
148
- subject,
149
- bodyLength: body.length,
150
- body,
151
- });
152
- if (opts.send) {
153
- await opts.send(input as z.infer<typeof emailInputSchema>);
154
- }
155
- return { sent: true, recipient: to };
156
- },
157
- });
158
- }