@dbx-tools/appkit-mastra 0.1.41 → 0.1.42
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/README.md +59 -58
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/src/agents.d.ts +3 -3
- package/dist/src/agents.js +1 -1
- package/dist/src/chart.d.ts +7 -1
- package/dist/src/chart.js +3 -5
- package/dist/src/config.d.ts +14 -11
- package/dist/src/genie.d.ts +0 -12
- package/dist/src/genie.js +2 -16
- package/dist/src/history.d.ts +6 -6
- package/dist/src/history.js +6 -6
- package/dist/src/model.d.ts +24 -131
- package/dist/src/model.js +39 -268
- package/dist/src/plugin.d.ts +13 -12
- package/dist/src/plugin.js +38 -34
- package/dist/src/server.d.ts +13 -20
- package/dist/src/server.js +15 -22
- package/dist/src/serving.d.ts +14 -98
- package/dist/src/serving.js +18 -163
- package/dist/src/tools/email.d.ts +10 -1
- package/dist/src/writer.d.ts +2 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/index.ts +2 -13
- package/package.json +6 -6
- package/src/agents.ts +3 -3
- package/src/chart.ts +3 -5
- package/src/config.ts +14 -11
- package/src/genie.ts +4 -22
- package/src/history.ts +6 -6
- package/src/model.ts +57 -291
- package/src/plugin.ts +45 -42
- package/src/server.ts +15 -22
- package/src/serving.ts +18 -220
- package/src/writer.ts +2 -2
- package/dist/src/intercept.d.ts +0 -48
- package/dist/src/intercept.js +0 -167
- package/src/intercept.ts +0 -206
package/index.ts
CHANGED
|
@@ -11,29 +11,18 @@
|
|
|
11
11
|
* consumers.
|
|
12
12
|
*/
|
|
13
13
|
export * from "@dbx-tools/appkit-mastra-shared";
|
|
14
|
+
export * from "@dbx-tools/model";
|
|
14
15
|
export * from "./src/agents.js";
|
|
15
16
|
export * from "./src/chart.js";
|
|
16
17
|
export * from "./src/config.js";
|
|
17
18
|
export * from "./src/genie.js";
|
|
18
|
-
export {
|
|
19
|
-
FALLBACK_MODEL_IDS,
|
|
20
|
-
MODEL_CATALOG,
|
|
21
|
-
ModelTier,
|
|
22
|
-
modelForTier,
|
|
23
|
-
modelsForTier,
|
|
24
|
-
} from "./src/model.js";
|
|
25
19
|
export * from "./src/plugin.js";
|
|
26
20
|
export {
|
|
27
21
|
MASTRA_MODEL_OVERRIDE_KEY,
|
|
28
22
|
MODEL_OVERRIDE_BODY_FIELDS,
|
|
29
23
|
MODEL_OVERRIDE_HEADER,
|
|
30
24
|
MODEL_OVERRIDE_QUERY,
|
|
31
|
-
clearServingEndpointsCache,
|
|
32
25
|
extractModelOverride,
|
|
33
|
-
|
|
34
|
-
resolveModelId,
|
|
35
|
-
type ResolveModelOptions,
|
|
36
|
-
type ResolvedModel,
|
|
37
|
-
type ServingEndpointSummary,
|
|
26
|
+
type ModelOverrideRequest,
|
|
38
27
|
} from "./src/serving.js";
|
|
39
28
|
export * from "./src/tools/email.js";
|
package/package.json
CHANGED
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"name": "@dbx-tools/appkit-mastra",
|
|
12
|
-
"version": "0.1.
|
|
12
|
+
"version": "0.1.42",
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@databricks/sdk-experimental": "^0.17",
|
|
15
|
-
"@dbx-tools/appkit-mastra-shared": "0.1.
|
|
16
|
-
"@dbx-tools/genie": "0.1.
|
|
17
|
-
"@dbx-tools/genie-shared": "0.1.
|
|
18
|
-
"@dbx-tools/
|
|
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",
|
|
19
20
|
"@mastra/ai-sdk": "^1",
|
|
20
21
|
"@mastra/core": "^1",
|
|
21
22
|
"@mastra/express": "^1",
|
|
@@ -24,7 +25,6 @@
|
|
|
24
25
|
"@mastra/observability": "^1",
|
|
25
26
|
"@mastra/otel-bridge": "^1",
|
|
26
27
|
"@mastra/pg": "^1",
|
|
27
|
-
"fuse.js": "^7.0.0",
|
|
28
28
|
"pg": "^8.20.0",
|
|
29
29
|
"zod": "^4.3.6"
|
|
30
30
|
},
|
package/src/agents.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* When no agents are registered the plugin falls back to a single
|
|
12
12
|
* built-in analyst so the bare `mastra()` call still mounts a working
|
|
13
|
-
*
|
|
13
|
+
* streamable agent for demos.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { appkitUtils, logUtils, stringUtils } from "@dbx-tools/shared";
|
|
@@ -226,8 +226,8 @@ export type MastraToolsFn = (
|
|
|
226
226
|
/**
|
|
227
227
|
* A code-defined Mastra agent. Mirrors the shape AppKit's `agents`
|
|
228
228
|
* plugin uses for `AgentDefinition`. The registry key under
|
|
229
|
-
* `config.agents` is
|
|
230
|
-
* informational (defaults to the key).
|
|
229
|
+
* `config.agents` is the `agentId` the client streams against; `name`
|
|
230
|
+
* is purely informational (defaults to the key).
|
|
231
231
|
*/
|
|
232
232
|
export interface MastraAgentDefinition {
|
|
233
233
|
/** Display name used as `Agent.name`. Defaults to the registry key. */
|
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,
|
|
42
|
+
import { buildModel, ModelTier } from "./model.js";
|
|
43
43
|
|
|
44
44
|
const log = logUtils.logger("mastra/chart");
|
|
45
45
|
|
|
@@ -330,9 +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, {
|
|
334
|
-
modelId: modelForTier(ModelTier.Fast),
|
|
335
|
-
}),
|
|
333
|
+
buildModel(config, requestContext, { tier: ModelTier.Fast }),
|
|
336
334
|
});
|
|
337
335
|
plannerAgents.set(config, agent);
|
|
338
336
|
}
|
|
@@ -361,7 +359,7 @@ async function runChartPlanner(
|
|
|
361
359
|
...(requestContext ? { requestContext } : {}),
|
|
362
360
|
...(abortSignal ? { abortSignal } : {}),
|
|
363
361
|
});
|
|
364
|
-
const plan = result.object
|
|
362
|
+
const plan = chartPlanSchema.parse(result.object);
|
|
365
363
|
const option = planToEchartsOption(plan, title);
|
|
366
364
|
return { chartType: plan.chartType, option };
|
|
367
365
|
}
|
package/src/config.ts
CHANGED
|
@@ -150,7 +150,8 @@ export interface MastraPluginConfig extends BasePluginConfig {
|
|
|
150
150
|
*/
|
|
151
151
|
tools?: MastraTools;
|
|
152
152
|
/**
|
|
153
|
-
* Agent id used
|
|
153
|
+
* Agent id used when the client doesn't specify one (the bare,
|
|
154
|
+
* un-suffixed history / suggestions routes resolve to it).
|
|
154
155
|
* Defaults to the first key in `agents` (or `"default"` when
|
|
155
156
|
* `agents` is omitted). Must match an id in `agents` when both are
|
|
156
157
|
* set; a mismatch throws at setup with the available candidates.
|
|
@@ -198,17 +199,19 @@ export interface MastraPluginConfig extends BasePluginConfig {
|
|
|
198
199
|
*/
|
|
199
200
|
modelOverride?: boolean;
|
|
200
201
|
/**
|
|
201
|
-
* Priority-ordered list of endpoint names tried when no
|
|
202
|
-
* plugin / env / request-override model id is set
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
202
|
+
* Priority-ordered list of endpoint names tried *first* when no
|
|
203
|
+
* agent / plugin / env / request-override model id is set, ahead of
|
|
204
|
+
* the dynamic score-classified catalogue. The resolver picks the
|
|
205
|
+
* first id that is actually present in the workspace's
|
|
206
|
+
* `/serving-endpoints` listing.
|
|
206
207
|
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
208
|
+
* When unset, resolution is driven by the live Foundation Model API
|
|
209
|
+
* `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
|
|
213
|
+
* pin a regulated workspace to an approved subset, or to put custom
|
|
214
|
+
* endpoints in front of the auto-classified catalogue.
|
|
212
215
|
*/
|
|
213
216
|
defaultModelFallbacks?: readonly string[];
|
|
214
217
|
/**
|
package/src/genie.ts
CHANGED
|
@@ -38,11 +38,11 @@ import { CacheManager, genie } from "@databricks/appkit";
|
|
|
38
38
|
import { ApiError, HttpError, WorkspaceClient } from "@databricks/sdk-experimental";
|
|
39
39
|
import {
|
|
40
40
|
ChartSchema,
|
|
41
|
-
type
|
|
41
|
+
type MastraWriter,
|
|
42
42
|
type StartedEvent,
|
|
43
43
|
} from "@dbx-tools/appkit-mastra-shared";
|
|
44
44
|
import { genieEventChat, genieSampleQuestions, getGenieSpace } from "@dbx-tools/genie";
|
|
45
|
-
import { type GenieMessage } from "@dbx-tools/genie-shared";
|
|
45
|
+
import { GenieMessageSchema, type GenieMessage } from "@dbx-tools/genie-shared";
|
|
46
46
|
import { appkitUtils, commonUtils, logUtils, stringUtils } from "@dbx-tools/shared";
|
|
47
47
|
import type { RequestContext } from "@mastra/core/request-context";
|
|
48
48
|
import { MASTRA_THREAD_ID_KEY } from "@mastra/core/request-context";
|
|
@@ -93,7 +93,7 @@ export type GenieSpacesConfig = Record<string, GenieSpaceConfig | string>;
|
|
|
93
93
|
type ToolExecuteCtx =
|
|
94
94
|
| {
|
|
95
95
|
requestContext?: RequestContext;
|
|
96
|
-
writer?:
|
|
96
|
+
writer?: MastraWriter;
|
|
97
97
|
abortSignal?: AbortSignal;
|
|
98
98
|
}
|
|
99
99
|
| undefined;
|
|
@@ -421,7 +421,7 @@ function buildAskGenieTool(opts: { spaceId: string; alias: string; hint?: string
|
|
|
421
421
|
question: z.string().min(1, "question is required"),
|
|
422
422
|
}),
|
|
423
423
|
outputSchema: z.object({
|
|
424
|
-
message:
|
|
424
|
+
message: GenieMessageSchema,
|
|
425
425
|
}),
|
|
426
426
|
execute: async ({ question }, ctxRaw) => {
|
|
427
427
|
const ctx = ctxRaw as ToolExecuteCtx;
|
|
@@ -1033,24 +1033,6 @@ export function buildGenieToolkitProvider(opts: {
|
|
|
1033
1033
|
};
|
|
1034
1034
|
}
|
|
1035
1035
|
|
|
1036
|
-
/**
|
|
1037
|
-
* Returns `true` when at least one Genie space is reachable
|
|
1038
|
-
* through {@link resolveGenieSpaces} - either via
|
|
1039
|
-
* {@link MastraPluginConfig.genieSpaces}, the AppKit `genie()`
|
|
1040
|
-
* plugin instance, or the `DATABRICKS_GENIE_SPACE_ID` env var.
|
|
1041
|
-
*
|
|
1042
|
-
* Cheap to call from `resolveProvider` to short-circuit `genie`
|
|
1043
|
-
* lookups when nothing is wired, so the `plugins.genie` lookup
|
|
1044
|
-
* still resolves to `undefined` (matching AppKit's
|
|
1045
|
-
* absent-plugin semantics) when neither source is configured.
|
|
1046
|
-
*/
|
|
1047
|
-
export function hasAnyGenieSpaces(
|
|
1048
|
-
config: MastraPluginConfig,
|
|
1049
|
-
context: appkitUtils.PluginContextLike | undefined,
|
|
1050
|
-
): boolean {
|
|
1051
|
-
return Object.keys(resolveGenieSpaces(config, context)).length > 0;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
1036
|
/* --------------------------- starter suggestions --------------------------- */
|
|
1055
1037
|
|
|
1056
1038
|
/**
|
package/src/history.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The route is registered through {@link historyRoute} as a Mastra
|
|
11
11
|
* `registerApiRoute` so it sits in the same dispatcher pipeline as
|
|
12
|
-
*
|
|
13
|
-
* `./server.ts`) has already populated `RequestContext` with
|
|
12
|
+
* the standard agent routes. That means the `MastraServer` auth
|
|
13
|
+
* middleware (in `./server.ts`) has already populated `RequestContext` with
|
|
14
14
|
* `MASTRA_THREAD_ID_KEY` and `MASTRA_RESOURCE_ID_KEY` by the time
|
|
15
15
|
* the handler runs - no cookie or user lookups happen here, and the
|
|
16
16
|
* session-cookie logic stays the single source of truth in `server.ts`.
|
|
@@ -197,10 +197,10 @@ export type HistoryRouteOptions =
|
|
|
197
197
|
* anchors the thread id is left alone so the user keeps the
|
|
198
198
|
* same thread - only the contents go away.
|
|
199
199
|
*
|
|
200
|
-
*
|
|
201
|
-
* fixed-agent mount, or include
|
|
202
|
-
*
|
|
203
|
-
*
|
|
200
|
+
* Follows the `@mastra/ai-sdk` `chatRoute` convention for agent
|
|
201
|
+
* binding: pass `agent` for a fixed-agent mount, or include
|
|
202
|
+
* `:agentId` in the path for dynamic routing. The plugin registers
|
|
203
|
+
* both `/route/history` (default agent) and `/route/history/:agentId`.
|
|
204
204
|
*
|
|
205
205
|
* The handler reads `threadId` and `resourceId` from `RequestContext`
|
|
206
206
|
* (populated upstream by `MastraServer.registerAuthMiddleware`), so
|
package/src/model.ts
CHANGED
|
@@ -7,237 +7,53 @@
|
|
|
7
7
|
* fresh bearer header, then point Mastra's OpenAI-compatible provider
|
|
8
8
|
* at `/serving-endpoints` on that host.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* names like `"claude sonnet"` resolve to the real endpoint name.
|
|
23
|
-
* Fuzzy matching is best-effort: when the workspace client throws
|
|
24
|
-
* (network blip, expired token at cache-fill time) we fall back to
|
|
25
|
-
* the input verbatim and let Databricks return the canonical error.
|
|
10
|
+
* This module only adds the Mastra-specific glue. The actual model
|
|
11
|
+
* selection - listing the workspace catalogue and resolving an
|
|
12
|
+
* explicit name / tier / fallback chain to a real endpoint id - lives
|
|
13
|
+
* in `@dbx-tools/model` ({@link selectModel}) so non-Mastra consumers
|
|
14
|
+
* (e.g. a job that just needs a model name) can reuse it. Here we
|
|
15
|
+
* assemble the explicit ask from Mastra's request context (the
|
|
16
|
+
* per-request override under {@link MASTRA_MODEL_OVERRIDE_KEY}, the
|
|
17
|
+
* agent / plugin `modelId`, or `DATABRICKS_SERVING_ENDPOINT_NAME`),
|
|
18
|
+
* pass the plugin's fuzzy / tier / fallback knobs through, and wrap
|
|
19
|
+
* the resolved id in the OpenAI-compatible provider config Mastra
|
|
20
|
+
* expects. Catalogue fetches fail loud: network / auth errors
|
|
21
|
+
* propagate so callers see the real SDK message.
|
|
26
22
|
*/
|
|
27
23
|
|
|
24
|
+
import { type ModelTier, parseModelTier, selectModel } from "@dbx-tools/model";
|
|
28
25
|
import { commonUtils, logUtils, netUtils, stringUtils } from "@dbx-tools/shared";
|
|
29
26
|
import type { MastraModelConfig } from "@mastra/core/llm";
|
|
30
27
|
import type { RequestContext } from "@mastra/core/request-context";
|
|
31
28
|
|
|
32
29
|
import { MASTRA_USER_KEY, type MastraPluginConfig, type User } from "./config.js";
|
|
33
|
-
import {
|
|
34
|
-
listServingEndpoints,
|
|
35
|
-
MASTRA_MODEL_OVERRIDE_KEY,
|
|
36
|
-
resolveModelId,
|
|
37
|
-
resolveServingConfig,
|
|
38
|
-
type ServingEndpointSummary,
|
|
39
|
-
} from "./serving.js";
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Capability tiers for Databricks Foundation Model API endpoints.
|
|
43
|
-
*
|
|
44
|
-
* - {@link ModelTier.Thinking}: deepest reasoning / "thinking" models
|
|
45
|
-
* (Claude Opus, GPT-5.5 Pro, Gemini Pro, Llama 4 Maverick, etc).
|
|
46
|
-
* Highest cost and latency; reserve for hard multi-step reasoning.
|
|
47
|
-
* - {@link ModelTier.Balanced}: cost/latency sweet spot for general
|
|
48
|
-
* agent work (Claude Sonnet, GPT-5.x, Gemini Flash, Llama 3.3 70B).
|
|
49
|
-
* The right default for most agents.
|
|
50
|
-
* - {@link ModelTier.Fast}: cheap and quick; classification, routing,
|
|
51
|
-
* tool-arg extraction, simple summarisation (Claude Haiku, GPT-5
|
|
52
|
-
* mini/nano, Gemini Flash Lite, GPT-OSS 20B, Llama 3.1 8B).
|
|
53
|
-
*
|
|
54
|
-
* String enum so the value is the slug we use in cache keys, logs,
|
|
55
|
-
* and as the value users see in serialized configs.
|
|
56
|
-
*/
|
|
57
|
-
export enum ModelTier {
|
|
58
|
-
Thinking = "thinking",
|
|
59
|
-
Balanced = "balanced",
|
|
60
|
-
Fast = "fast",
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Catalogue of Databricks-hosted Foundation Model API endpoints,
|
|
65
|
-
* grouped by capability {@link ModelTier} and then by provider. Each
|
|
66
|
-
* inner array is priority-ordered (most powerful first within the
|
|
67
|
-
* same provider+tier).
|
|
68
|
-
*
|
|
69
|
-
* Provider buckets:
|
|
70
|
-
*
|
|
71
|
-
* - `claude`: Anthropic Claude family (closed; flagship reasoning).
|
|
72
|
-
* - `gpt`: OpenAI GPT-5 family (closed; "ChatGPT" on Databricks FMAPI).
|
|
73
|
-
* - `gemini`: Google Gemini family (closed; multimodal + web-search).
|
|
74
|
-
* - `openSource`: open-weights models (widest regional / SKU availability).
|
|
75
|
-
*
|
|
76
|
-
* The list is curated by hand; refresh from the Databricks "supported
|
|
77
|
-
* foundation models" doc when new endpoints land.
|
|
78
|
-
*/
|
|
79
|
-
export const MODEL_CATALOG = {
|
|
80
|
-
[ModelTier.Thinking]: {
|
|
81
|
-
claude: [
|
|
82
|
-
"databricks-claude-opus-4-8",
|
|
83
|
-
"databricks-claude-opus-4-7",
|
|
84
|
-
"databricks-claude-opus-4-6",
|
|
85
|
-
"databricks-claude-opus-4-5",
|
|
86
|
-
"databricks-claude-opus-4-1",
|
|
87
|
-
],
|
|
88
|
-
gpt: ["databricks-gpt-5-5-pro"],
|
|
89
|
-
gemini: [
|
|
90
|
-
"databricks-gemini-3-1-pro",
|
|
91
|
-
"databricks-gemini-3-pro",
|
|
92
|
-
"databricks-gemini-2-5-pro",
|
|
93
|
-
],
|
|
94
|
-
openSource: [
|
|
95
|
-
"databricks-llama-4-maverick",
|
|
96
|
-
"databricks-gpt-oss-120b",
|
|
97
|
-
"databricks-meta-llama-3-1-405b-instruct",
|
|
98
|
-
],
|
|
99
|
-
},
|
|
100
|
-
[ModelTier.Balanced]: {
|
|
101
|
-
claude: [
|
|
102
|
-
"databricks-claude-sonnet-4-6",
|
|
103
|
-
"databricks-claude-sonnet-4-5",
|
|
104
|
-
"databricks-claude-sonnet-4",
|
|
105
|
-
],
|
|
106
|
-
gpt: [
|
|
107
|
-
"databricks-gpt-5-5",
|
|
108
|
-
"databricks-gpt-5-4",
|
|
109
|
-
"databricks-gpt-5-2",
|
|
110
|
-
"databricks-gpt-5-1",
|
|
111
|
-
"databricks-gpt-5",
|
|
112
|
-
],
|
|
113
|
-
gemini: [
|
|
114
|
-
"databricks-gemini-3-5-flash",
|
|
115
|
-
"databricks-gemini-3-flash",
|
|
116
|
-
"databricks-gemini-2-5-flash",
|
|
117
|
-
],
|
|
118
|
-
openSource: [
|
|
119
|
-
"databricks-meta-llama-3-3-70b-instruct",
|
|
120
|
-
"databricks-qwen3-next-80b-a3b-instruct",
|
|
121
|
-
"databricks-qwen35-122b-a10b",
|
|
122
|
-
],
|
|
123
|
-
},
|
|
124
|
-
[ModelTier.Fast]: {
|
|
125
|
-
claude: ["databricks-claude-haiku-4-5"],
|
|
126
|
-
gpt: [
|
|
127
|
-
"databricks-gpt-5-4-mini",
|
|
128
|
-
"databricks-gpt-5-4-nano",
|
|
129
|
-
"databricks-gpt-5-mini",
|
|
130
|
-
"databricks-gpt-5-nano",
|
|
131
|
-
],
|
|
132
|
-
gemini: ["databricks-gemini-3-1-flash-lite"],
|
|
133
|
-
openSource: [
|
|
134
|
-
"databricks-gpt-oss-20b",
|
|
135
|
-
"databricks-gemma-3-12b",
|
|
136
|
-
"databricks-meta-llama-3-1-8b-instruct",
|
|
137
|
-
],
|
|
138
|
-
},
|
|
139
|
-
} as const satisfies Record<ModelTier, Record<string, readonly string[]>>;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Round-robin zip: take one from each input list in order, skipping
|
|
143
|
-
* lists that have already been exhausted. Used to interleave provider
|
|
144
|
-
* buckets within a tier so the resolver alternates between vendors
|
|
145
|
-
* instead of draining one before trying the next.
|
|
146
|
-
*
|
|
147
|
-
* Example: `interleave(["a1","a2","a3"], ["b1","b2"])` ->
|
|
148
|
-
* `["a1","b1","a2","b2","a3"]`.
|
|
149
|
-
*/
|
|
150
|
-
function interleave<T>(...lists: readonly (readonly T[])[]): T[] {
|
|
151
|
-
const out: T[] = [];
|
|
152
|
-
const max = Math.max(0, ...lists.map((l) => l.length));
|
|
153
|
-
for (let i = 0; i < max; i++) {
|
|
154
|
-
for (const list of lists) {
|
|
155
|
-
if (i < list.length) out.push(list[i]!);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return out;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Priority-ordered model ids for a single capability {@link ModelTier},
|
|
163
|
-
* interleaved across providers so a workspace missing the top Claude
|
|
164
|
-
* still lands on a flagship GPT / Gemini on the next probe.
|
|
165
|
-
*
|
|
166
|
-
* Provider order within the interleave: Claude, GPT, Gemini, then the
|
|
167
|
-
* open-weights tail appended verbatim as the universal floor (widest
|
|
168
|
-
* regional availability).
|
|
169
|
-
*
|
|
170
|
-
* @example
|
|
171
|
-
* ```ts
|
|
172
|
-
* mastra({
|
|
173
|
-
* defaultModelFallbacks: modelsForTier(ModelTier.Fast),
|
|
174
|
-
* });
|
|
175
|
-
* ```
|
|
176
|
-
*/
|
|
177
|
-
export function modelsForTier(tier: ModelTier): readonly string[] {
|
|
178
|
-
const bucket = MODEL_CATALOG[tier];
|
|
179
|
-
return [
|
|
180
|
-
...interleave(bucket.claude, bucket.gpt, bucket.gemini),
|
|
181
|
-
...bucket.openSource,
|
|
182
|
-
];
|
|
183
|
-
}
|
|
30
|
+
import { MASTRA_MODEL_OVERRIDE_KEY, resolveServingConfig } from "./serving.js";
|
|
184
31
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
* @example
|
|
193
|
-
* ```ts
|
|
194
|
-
* const classifier = createAgent({
|
|
195
|
-
* instructions: "Classify this email",
|
|
196
|
-
* model: modelForTier(ModelTier.Fast), // cheap, quick
|
|
197
|
-
* });
|
|
198
|
-
*
|
|
199
|
-
* const planner = createAgent({
|
|
200
|
-
* instructions: "Plan a multi-step migration",
|
|
201
|
-
* model: modelForTier(ModelTier.Thinking), // deep reasoning
|
|
202
|
-
* });
|
|
203
|
-
* ```
|
|
204
|
-
*/
|
|
205
|
-
export function modelForTier(tier: ModelTier): string {
|
|
206
|
-
return modelsForTier(tier)[0]!;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Last-resort model ids used when neither `config.defaultModel`,
|
|
211
|
-
* per-agent `model`, nor `DATABRICKS_SERVING_ENDPOINT_NAME` is set.
|
|
212
|
-
*
|
|
213
|
-
* Walked in order at resolve time: the first id whose endpoint is
|
|
214
|
-
* actually present in the workspace's `/serving-endpoints` listing
|
|
215
|
-
* wins. Workspaces vary - not every region / SKU has every model,
|
|
216
|
-
* and the list of Foundation Model APIs evolves quickly - so the
|
|
217
|
-
* resolver degrades all the way from "best thinking model" down to
|
|
218
|
-
* "smallest commodity Llama" before giving up.
|
|
219
|
-
*
|
|
220
|
-
* Built by chaining the per-tier interleaves (Thinking -> Balanced
|
|
221
|
-
* -> Fast); within each tier the providers are round-robin-zipped
|
|
222
|
-
* (Claude, GPT, Gemini, then open-weights tail). Override the entire
|
|
223
|
-
* list via `MastraPluginConfig.defaultModelFallbacks` (e.g. to pin a
|
|
224
|
-
* regulated workspace to a specific approved subset, or to bias the
|
|
225
|
-
* priority toward a particular tier).
|
|
226
|
-
*/
|
|
227
|
-
export const FALLBACK_MODEL_IDS: readonly string[] = [
|
|
228
|
-
...modelsForTier(ModelTier.Thinking),
|
|
229
|
-
...modelsForTier(ModelTier.Balanced),
|
|
230
|
-
...modelsForTier(ModelTier.Fast),
|
|
231
|
-
];
|
|
32
|
+
export {
|
|
33
|
+
classifyEndpoints,
|
|
34
|
+
FALLBACK_MODEL_IDS,
|
|
35
|
+
modelForTier,
|
|
36
|
+
modelsForTier,
|
|
37
|
+
ModelTier,
|
|
38
|
+
} from "@dbx-tools/model";
|
|
232
39
|
|
|
233
40
|
/** Optional overrides accepted by {@link buildModel}. */
|
|
234
41
|
export interface BuildModelOverrides {
|
|
235
42
|
/**
|
|
236
43
|
* Static model id from the agent / plugin config (string sugar on
|
|
237
44
|
* `def.model` or `config.defaultModel`). Loses to the per-request
|
|
238
|
-
* override but wins over env / fallback.
|
|
45
|
+
* override but wins over env / tier / fallback.
|
|
239
46
|
*/
|
|
240
47
|
modelId?: string;
|
|
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
|
|
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.
|
|
55
|
+
*/
|
|
56
|
+
tier?: ModelTier;
|
|
241
57
|
}
|
|
242
58
|
|
|
243
59
|
/**
|
|
@@ -262,91 +78,41 @@ export async function buildModel(
|
|
|
262
78
|
// well-formed (`/serving-endpoints/chat/completions`).
|
|
263
79
|
const url = new URL("/serving-endpoints", host).toString().replace(/\/$/, "");
|
|
264
80
|
|
|
265
|
-
const modelId = await pickModelId(config, requestContext, overrides, user, host);
|
|
266
|
-
|
|
267
|
-
return {
|
|
268
|
-
providerId: config.providerId ?? "databricks",
|
|
269
|
-
modelId,
|
|
270
|
-
url,
|
|
271
|
-
headers: Object.fromEntries(headers.entries()),
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Walk the resolution ladder and pick a modelId.
|
|
277
|
-
*
|
|
278
|
-
* 1. **Explicit ask** (per-request override, agent `model` string,
|
|
279
|
-
* `config.defaultModel` string, or `DATABRICKS_SERVING_ENDPOINT_NAME`):
|
|
280
|
-
* when fuzzy matching is on, snap the input to the closest live
|
|
281
|
-
* endpoint so loose names like `"claude sonnet"` resolve. When it's
|
|
282
|
-
* off (or no endpoint matches within threshold), the input is used
|
|
283
|
-
* verbatim and Databricks surfaces the canonical 404.
|
|
284
|
-
*
|
|
285
|
-
* 2. **No explicit ask**: walk
|
|
286
|
-
* {@link MastraPluginConfig.defaultModelFallbacks} (or
|
|
287
|
-
* {@link FALLBACK_MODEL_IDS} when unset) and return the first id
|
|
288
|
-
* whose endpoint is actually present in the workspace listing. A
|
|
289
|
-
* workspace without Claude Opus still gets a sensible default by
|
|
290
|
-
* skipping ahead to whichever Sonnet / GPT-5 / Llama variant is
|
|
291
|
-
* wired up.
|
|
292
|
-
*
|
|
293
|
-
* Catalogue fetches fail loud: network / auth errors propagate to the
|
|
294
|
-
* caller so they see the real SDK message instead of a silent fallback
|
|
295
|
-
* to the top of the priority list.
|
|
296
|
-
*/
|
|
297
|
-
async function pickModelId(
|
|
298
|
-
config: MastraPluginConfig,
|
|
299
|
-
requestContext: RequestContext,
|
|
300
|
-
overrides: BuildModelOverrides,
|
|
301
|
-
user: User,
|
|
302
|
-
host: string,
|
|
303
|
-
): Promise<string> {
|
|
304
81
|
const log = logUtils.logger(config);
|
|
305
|
-
const serving = resolveServingConfig(config
|
|
82
|
+
const serving = resolveServingConfig(config);
|
|
306
83
|
const override = serving.allowOverride
|
|
307
84
|
? (requestContext.get(MASTRA_MODEL_OVERRIDE_KEY) as string | undefined)
|
|
308
85
|
: undefined;
|
|
309
|
-
const explicit =
|
|
310
|
-
override ?? overrides.modelId ?? process.env.DATABRICKS_SERVING_ENDPOINT_NAME;
|
|
311
86
|
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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.
|
|
94
|
+
const requested =
|
|
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;
|
|
318
99
|
|
|
319
|
-
const
|
|
100
|
+
const { modelId, source } = await selectModel(user.executionContext.client, host, {
|
|
101
|
+
...(explicit !== undefined ? { explicit } : {}),
|
|
102
|
+
fuzzy: serving.fuzzy,
|
|
103
|
+
threshold: serving.threshold,
|
|
104
|
+
...(tier !== undefined ? { tier } : {}),
|
|
105
|
+
fallbacks: serving.fallbacks,
|
|
320
106
|
ttlMs: serving.ttlMs,
|
|
321
107
|
});
|
|
322
|
-
|
|
323
|
-
explicit !== undefined
|
|
324
|
-
? resolveModelId(explicit, endpoints, { threshold: serving.threshold }).modelId
|
|
325
|
-
: pickFirstAvailable(serving.fallbacks, endpoints);
|
|
326
|
-
log.debug("model selected", {
|
|
327
|
-
modelId,
|
|
328
|
-
source: explicit !== undefined ? "fuzzy-match" : "fallback",
|
|
329
|
-
requestedExplicit: explicit,
|
|
330
|
-
});
|
|
331
|
-
return modelId;
|
|
332
|
-
}
|
|
108
|
+
log.debug("model selected", { modelId, source, requested });
|
|
333
109
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
*/
|
|
341
|
-
function pickFirstAvailable(
|
|
342
|
-
fallbacks: readonly string[],
|
|
343
|
-
endpoints: readonly ServingEndpointSummary[],
|
|
344
|
-
): string {
|
|
345
|
-
const present = new Set(endpoints.map((e) => e.name));
|
|
346
|
-
for (const candidate of fallbacks) {
|
|
347
|
-
if (present.has(candidate)) return candidate;
|
|
348
|
-
}
|
|
349
|
-
return fallbacks[0] ?? FALLBACK_MODEL_IDS[0]!;
|
|
110
|
+
return {
|
|
111
|
+
providerId: config.providerId ?? "databricks",
|
|
112
|
+
modelId,
|
|
113
|
+
url,
|
|
114
|
+
headers: Object.fromEntries(headers.entries()),
|
|
115
|
+
};
|
|
350
116
|
}
|
|
351
117
|
|
|
352
118
|
/** Path prefix that identifies a Databricks Model Serving REST call. */
|