@dbx-tools/appkit-mastra 0.1.4 → 0.1.9
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 +304 -503
- package/index.ts +46 -36
- package/package.json +58 -47
- package/src/agents.ts +255 -72
- package/src/chart.ts +695 -0
- package/src/config.ts +282 -18
- package/src/filesystems.ts +1090 -0
- package/src/genie.ts +1025 -288
- package/src/history.ts +297 -0
- package/src/mcp.ts +105 -0
- package/src/memory.ts +129 -74
- package/src/mlflow.ts +149 -0
- package/src/model.ts +80 -408
- package/src/observability.ts +144 -0
- package/src/pagination.ts +34 -0
- package/src/plugin.ts +587 -52
- package/src/processors.ts +168 -0
- package/src/rest.ts +67 -0
- package/src/server.ts +292 -80
- package/src/serving-sanitize.ts +167 -0
- package/src/serving.ts +27 -224
- package/src/statement.ts +89 -0
- package/src/storage-schema.ts +41 -0
- package/src/summarize.ts +176 -0
- package/src/threads.ts +338 -0
- package/src/workspaces.ts +346 -0
- package/src/writer.ts +44 -0
- package/tsconfig.json +41 -0
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -18
- package/dist/src/agents.d.ts +0 -306
- package/dist/src/agents.js +0 -379
- package/dist/src/config.d.ts +0 -170
- package/dist/src/config.js +0 -12
- package/dist/src/genie.d.ts +0 -109
- package/dist/src/genie.js +0 -271
- package/dist/src/memory.d.ts +0 -79
- package/dist/src/memory.js +0 -197
- package/dist/src/model.d.ts +0 -159
- package/dist/src/model.js +0 -423
- package/dist/src/plugin.d.ts +0 -120
- package/dist/src/plugin.js +0 -235
- package/dist/src/server.d.ts +0 -42
- package/dist/src/server.js +0 -109
- package/dist/src/serving.d.ts +0 -156
- package/dist/src/serving.js +0 -214
package/src/agents.ts
CHANGED
|
@@ -10,21 +10,27 @@
|
|
|
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
|
-
import { genie } from "@databricks/appkit";
|
|
17
|
-
import { logUtils, pluginUtils, stringUtils } from "@dbx-tools/appkit-shared";
|
|
18
|
-
import { Agent } from "@mastra/core/agent";
|
|
19
16
|
import type { AgentConfig, ToolsInput } from "@mastra/core/agent";
|
|
20
|
-
import {
|
|
17
|
+
import { Agent } from "@mastra/core/agent";
|
|
21
18
|
import type { Tool } from "@mastra/core/tools";
|
|
19
|
+
import { createTool } from "@mastra/core/tools";
|
|
20
|
+
import type { Workspace } from "@mastra/core/workspace";
|
|
22
21
|
import type { PgVectorConfig, PostgresStoreConfig } from "@mastra/pg";
|
|
23
22
|
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
26
|
-
import
|
|
27
|
-
import {
|
|
23
|
+
import { buildRenderDataTool } from "./chart";
|
|
24
|
+
import type { MastraPluginConfig } from "./config";
|
|
25
|
+
import { buildGenieToolkitProvider, resolveGenieSpaces } from "./genie";
|
|
26
|
+
import type { MemoryBuilder } from "./memory";
|
|
27
|
+
import { buildModel } from "./model";
|
|
28
|
+
import { fallback } from "@dbx-tools/model";
|
|
29
|
+
import { ResultProcessor, stripStaleChartsProcessor } from "./processors";
|
|
30
|
+
import { buildSummarizeTool } from "./summarize";
|
|
31
|
+
import { createWorkspace } from "./workspaces";
|
|
32
|
+
import { log, string } from "@dbx-tools/shared-core";
|
|
33
|
+
import { plugin } from "@dbx-tools/appkit";
|
|
28
34
|
|
|
29
35
|
/**
|
|
30
36
|
* Tool record accepted by every Mastra `Agent.tools` field and by the
|
|
@@ -120,12 +126,12 @@ export interface AppKitToolOptions {
|
|
|
120
126
|
|
|
121
127
|
/**
|
|
122
128
|
* Build a deterministic Mastra tool id from a description.
|
|
123
|
-
* Delegates to {@link
|
|
124
|
-
*
|
|
125
|
-
* collide in traces. Stable across runs.
|
|
129
|
+
* Delegates to {@link string.toUniqueSlug}: slug + always-on
|
|
130
|
+
* 6-char FNV-1a base-32 suffix so two tools with the same leading
|
|
131
|
+
* words don't collide in traces. Stable across runs.
|
|
126
132
|
*/
|
|
127
133
|
function deriveToolId(description: string): string {
|
|
128
|
-
return
|
|
134
|
+
return string.toUniqueSlug(description, { fallbackPrefix: "tool" });
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
/**
|
|
@@ -144,7 +150,8 @@ function deriveToolId(description: string): string {
|
|
|
144
150
|
* type inference and to match the AppKit API surface.
|
|
145
151
|
*/
|
|
146
152
|
export function createAgent<T extends MastraAgentDefinition>(def: T): T {
|
|
147
|
-
|
|
153
|
+
const workspace = def.workspace ?? createWorkspace();
|
|
154
|
+
return { ...def, workspace };
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
/**
|
|
@@ -217,15 +224,16 @@ export interface MastraPluginToolkitProvider {
|
|
|
217
224
|
export type MastraPlugins = Record<string, MastraPluginToolkitProvider>;
|
|
218
225
|
|
|
219
226
|
/** Function form of {@link MastraAgentDefinition.tools}. */
|
|
220
|
-
export type MastraToolsFn = (
|
|
221
|
-
|
|
222
|
-
|
|
227
|
+
export type MastraToolsFn = (plugins: MastraPlugins) => MastraTools | Promise<MastraTools>;
|
|
228
|
+
|
|
229
|
+
/** Function form of {@link MastraAgentDefinition.workspace}. */
|
|
230
|
+
export type MastraAgentWorkspaceResolver = () => Workspace | undefined;
|
|
223
231
|
|
|
224
232
|
/**
|
|
225
233
|
* A code-defined Mastra agent. Mirrors the shape AppKit's `agents`
|
|
226
234
|
* plugin uses for `AgentDefinition`. The registry key under
|
|
227
|
-
* `config.agents` is
|
|
228
|
-
* informational (defaults to the key).
|
|
235
|
+
* `config.agents` is the `agentId` the client streams against; `name`
|
|
236
|
+
* is purely informational (defaults to the key).
|
|
229
237
|
*/
|
|
230
238
|
export interface MastraAgentDefinition {
|
|
231
239
|
/** Display name used as `Agent.name`. Defaults to the registry key. */
|
|
@@ -274,7 +282,7 @@ export interface MastraAgentDefinition {
|
|
|
274
282
|
*
|
|
275
283
|
* - `undefined` (default): inherit `config.storage`. When that's
|
|
276
284
|
* enabled, the agent gets its **own per-agent `PostgresStore`**
|
|
277
|
-
* keyed by
|
|
285
|
+
* keyed by {@link agentStorageSchemaName} so threads and
|
|
278
286
|
* messages stay isolated between agents in the same database.
|
|
279
287
|
* - `false`: disable storage for this agent only (purely in-memory).
|
|
280
288
|
* - `true`: enable with the per-agent default schema.
|
|
@@ -282,6 +290,12 @@ export interface MastraAgentDefinition {
|
|
|
282
290
|
* `PostgresStore` config (custom schema, connection, etc.).
|
|
283
291
|
*/
|
|
284
292
|
storage?: boolean | MastraStorageConfigOverride;
|
|
293
|
+
/**
|
|
294
|
+
* Mastra {@link Workspace} for this agent (filesystem, sandbox, or other
|
|
295
|
+
* providers). Assistant skills from Databricks workspace paths are wired
|
|
296
|
+
* via {@link createWorkspace}.
|
|
297
|
+
*/
|
|
298
|
+
workspace?: Workspace | MastraAgentWorkspaceResolver;
|
|
285
299
|
}
|
|
286
300
|
|
|
287
301
|
/**
|
|
@@ -290,19 +304,16 @@ export interface MastraAgentDefinition {
|
|
|
290
304
|
* strip `id`. The built-in `Omit` collapses unions to one shape with
|
|
291
305
|
* common fields only, which loses the connection-style discriminants.
|
|
292
306
|
*/
|
|
293
|
-
type DistributiveOmit<T, K extends keyof never> = T extends unknown
|
|
294
|
-
? Omit<T, K>
|
|
295
|
-
: never;
|
|
307
|
+
type DistributiveOmit<T, K extends keyof never> = T extends unknown ? Omit<T, K> : never;
|
|
296
308
|
|
|
297
309
|
/**
|
|
298
310
|
* `PostgresStoreConfig` minus `id` - per-agent overrides accept any
|
|
299
311
|
* Mastra-supported storage shape. `id` is filled in automatically
|
|
300
312
|
* from the agent registry key so traces stay stable.
|
|
301
313
|
*/
|
|
302
|
-
export type MastraStorageConfigOverride = DistributiveOmit<
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
> & { id?: string };
|
|
314
|
+
export type MastraStorageConfigOverride = DistributiveOmit<PostgresStoreConfig, "id"> & {
|
|
315
|
+
id?: string;
|
|
316
|
+
};
|
|
306
317
|
|
|
307
318
|
/**
|
|
308
319
|
* `PgVectorConfig` minus `id` - per-agent overrides accept any
|
|
@@ -317,11 +328,28 @@ export type MastraMemoryConfigOverride = DistributiveOmit<PgVectorConfig, "id">
|
|
|
317
328
|
export interface BuiltAgents {
|
|
318
329
|
agents: Record<string, Agent>;
|
|
319
330
|
defaultAgentId: string;
|
|
331
|
+
/**
|
|
332
|
+
* Ambient tools shared across every agent (the built-in system tools
|
|
333
|
+
* spread with `config.tools`). Surfaced so the optional MCP server
|
|
334
|
+
* can re-expose them when {@link MastraMcpConfig.tools} is enabled.
|
|
335
|
+
*/
|
|
336
|
+
ambientTools: MastraTools;
|
|
320
337
|
}
|
|
321
338
|
|
|
322
339
|
/** Fallback agent id used when `config.agents` is omitted entirely. */
|
|
323
340
|
export const FALLBACK_AGENT_ID = "default";
|
|
324
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Default per-turn step ceiling applied to every registered agent
|
|
344
|
+
* when {@link MastraPluginConfig.agentMaxSteps} is unset. Sized to
|
|
345
|
+
* fit a decomposed Genie turn (grounding + several `ask_genie`
|
|
346
|
+
* calls + `prepare_chart` per dataset + the final-text reply) with
|
|
347
|
+
* headroom for the model to chain a couple of follow-ups before
|
|
348
|
+
* answering - well above Mastra's own `agent.generate` default of
|
|
349
|
+
* 5, which would cut multi-step orchestration off mid-loop.
|
|
350
|
+
*/
|
|
351
|
+
export const DEFAULT_AGENT_MAX_STEPS = 25;
|
|
352
|
+
|
|
325
353
|
const FALLBACK_AGENT_INSTRUCTIONS = `You are a data analyst. The user will ask questions about
|
|
326
354
|
business metrics and may share personal preferences you should remember across turns.
|
|
327
355
|
|
|
@@ -344,16 +372,21 @@ Rules:
|
|
|
344
372
|
* Override globally via {@link MastraPluginConfig.styleInstructions}
|
|
345
373
|
* (pass `false` to disable entirely, or a string to replace).
|
|
346
374
|
*/
|
|
347
|
-
export const DEFAULT_STYLE_INSTRUCTIONS =
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
375
|
+
export const DEFAULT_STYLE_INSTRUCTIONS = [
|
|
376
|
+
"Output style:",
|
|
377
|
+
"",
|
|
378
|
+
"Use markdown formatting, including headings, lists, and code blocks.",
|
|
379
|
+
"Avoid lists and headers for short replies.",
|
|
380
|
+
"Plain prose.",
|
|
381
|
+
"Use hyphens (-) only. Never use em dashes or en dashes.",
|
|
382
|
+
"Never use emojis.",
|
|
383
|
+
"Skip openers like 'Great question', 'Absolutely', and 'I'd be happy to help'.",
|
|
384
|
+
"Skip closers like 'Let me know if you have any questions'.",
|
|
385
|
+
"Skip self-disclaimers like 'I should mention' and 'It's important to note'.",
|
|
386
|
+
"Answer directly.",
|
|
387
|
+
"Do not include a preamble before the actual answer.",
|
|
388
|
+
"Use lists and headers only when they clarify a multi-part answer.",
|
|
389
|
+
].join("\n");
|
|
357
390
|
|
|
358
391
|
/**
|
|
359
392
|
* Resolve the style block to append to every agent's instructions.
|
|
@@ -364,6 +397,7 @@ function resolveStyleInstructions(config: MastraPluginConfig): string | null {
|
|
|
364
397
|
if (typeof config.styleInstructions === "string") {
|
|
365
398
|
return config.styleInstructions;
|
|
366
399
|
}
|
|
400
|
+
|
|
367
401
|
return DEFAULT_STYLE_INSTRUCTIONS;
|
|
368
402
|
}
|
|
369
403
|
|
|
@@ -371,14 +405,21 @@ function resolveStyleInstructions(config: MastraPluginConfig): string | null {
|
|
|
371
405
|
* Join an agent's bespoke instructions with the resolved style block.
|
|
372
406
|
* Returns the bespoke text unchanged when the style block is disabled.
|
|
373
407
|
*/
|
|
374
|
-
function composeInstructions(
|
|
375
|
-
agentInstructions: string,
|
|
376
|
-
style: string | null,
|
|
377
|
-
): string {
|
|
408
|
+
function composeInstructions(agentInstructions: string, style: string | null): string {
|
|
378
409
|
if (!style) return agentInstructions;
|
|
379
410
|
return `${agentInstructions.trimEnd()}\n\n${style}`;
|
|
380
411
|
}
|
|
381
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Generated description for an agent whose definition omits one. Kept
|
|
415
|
+
* generic (the agent's own name is the only reliable signal at build
|
|
416
|
+
* time) so it reads sensibly as the `ask_<id>` MCP tool's description
|
|
417
|
+
* and in agent metadata.
|
|
418
|
+
*/
|
|
419
|
+
function defaultAgentDescription(name: string): string {
|
|
420
|
+
return `Conversational AI agent "${name}".`;
|
|
421
|
+
}
|
|
422
|
+
|
|
382
423
|
/**
|
|
383
424
|
* Resolve every entry in `config.agents` into a Mastra `Agent`
|
|
384
425
|
* instance. When `config.agents` is omitted the plugin registers a
|
|
@@ -394,31 +435,78 @@ function composeInstructions(
|
|
|
394
435
|
*/
|
|
395
436
|
export async function buildAgents(opts: {
|
|
396
437
|
config: MastraPluginConfig;
|
|
397
|
-
context:
|
|
438
|
+
context: plugin.PluginContextLike | undefined;
|
|
398
439
|
memoryBuilder?: MemoryBuilder;
|
|
399
|
-
log:
|
|
440
|
+
log: log.Logger;
|
|
400
441
|
}): Promise<BuiltAgents> {
|
|
401
442
|
const { config, context, memoryBuilder, log } = opts;
|
|
402
443
|
const definitions = resolveDefinitions(config);
|
|
403
444
|
const ids = Object.keys(definitions);
|
|
404
445
|
const defaultAgentId = config.defaultAgent ?? ids[0] ?? FALLBACK_AGENT_ID;
|
|
405
446
|
|
|
406
|
-
const plugins = buildPluginsMap(context);
|
|
407
|
-
|
|
447
|
+
const plugins = buildPluginsMap(config, context);
|
|
448
|
+
// System-default ambient tools every agent gets out of the box:
|
|
449
|
+
// `render_data` for inline visualizations and `summarize` for
|
|
450
|
+
// offloading text condensing to the fast / small chat tier. The
|
|
451
|
+
// user can shadow either by including a same-named tool in their own
|
|
452
|
+
// `config.tools` or per-agent `tools`. Order in {@link resolveTools}
|
|
453
|
+
// is `system -> user-ambient -> per-agent`, last write wins.
|
|
454
|
+
const systemTools: MastraTools = {
|
|
455
|
+
render_data: buildRenderDataTool(config),
|
|
456
|
+
summarize: buildSummarizeTool(config),
|
|
457
|
+
};
|
|
458
|
+
const ambientTools = {
|
|
459
|
+
...systemTools,
|
|
460
|
+
...(config.tools ?? {}),
|
|
461
|
+
};
|
|
408
462
|
const style = resolveStyleInstructions(config);
|
|
463
|
+
// Default-on protection against the model copying turn-scoped
|
|
464
|
+
// chartIds from prior assistant tool results into the new
|
|
465
|
+
// turn's `[chart:<id>]` markers. Opt out per-plugin via
|
|
466
|
+
// `config.stripStaleCharts: false`.
|
|
467
|
+
const outputProcessors = [new ResultProcessor()];
|
|
468
|
+
const inputProcessors = [
|
|
469
|
+
...(config.stripStaleCharts === false ? [] : [stripStaleChartsProcessor]),
|
|
470
|
+
];
|
|
409
471
|
const agents: Record<string, Agent> = {};
|
|
472
|
+
const approvalGatedByAgent: Array<{ agentId: string; toolIds: string[] }> = [];
|
|
410
473
|
|
|
411
474
|
for (const [id, def] of Object.entries(definitions)) {
|
|
412
475
|
const tools = await resolveTools(def.tools, plugins, ambientTools);
|
|
476
|
+
const workspace = resolveAgentWorkspace(def.workspace);
|
|
477
|
+
const gated = approvalGatedToolIds(tools);
|
|
478
|
+
if (gated.length > 0) approvalGatedByAgent.push({ agentId: id, toolIds: gated });
|
|
413
479
|
const memory = memoryBuilder?.forAgent(id, def);
|
|
414
480
|
agents[id] = new Agent({
|
|
415
481
|
id,
|
|
416
482
|
name: def.name ?? id,
|
|
417
|
-
|
|
483
|
+
// Always carry a non-empty description: it's surfaced to MCP
|
|
484
|
+
// clients (which reject a description-less agent) and in agent
|
|
485
|
+
// metadata. Fall back to a generated one when the definition
|
|
486
|
+
// omits it.
|
|
487
|
+
description: def.description?.trim() || defaultAgentDescription(def.name ?? id),
|
|
418
488
|
instructions: composeInstructions(def.instructions, style),
|
|
419
489
|
model: resolveModel(config, def.model),
|
|
490
|
+
defaultOptions: {
|
|
491
|
+
maxSteps: config.agentMaxSteps ?? DEFAULT_AGENT_MAX_STEPS,
|
|
492
|
+
},
|
|
420
493
|
tools,
|
|
421
494
|
...(memory ? { memory } : {}),
|
|
495
|
+
...(workspace ? { workspace } : {}),
|
|
496
|
+
inputProcessors,
|
|
497
|
+
outputProcessors,
|
|
498
|
+
});
|
|
499
|
+
// Surface the effective default model per agent so operators can
|
|
500
|
+
// see at a glance which endpoint each agent points at without
|
|
501
|
+
// having to fire a request and inspect a trace. The value is the
|
|
502
|
+
// *static* default; per-request overrides (header / query /
|
|
503
|
+
// body) and the workspace-catalogue fuzzy match still apply at
|
|
504
|
+
// call time.
|
|
505
|
+
log.info("agent registered", {
|
|
506
|
+
id,
|
|
507
|
+
name: def.name ?? id,
|
|
508
|
+
defaultModel: describeAgentDefaultModel(config, def),
|
|
509
|
+
tools: Object.keys(tools),
|
|
422
510
|
});
|
|
423
511
|
}
|
|
424
512
|
|
|
@@ -428,8 +516,88 @@ export async function buildAgents(opts: {
|
|
|
428
516
|
);
|
|
429
517
|
}
|
|
430
518
|
|
|
431
|
-
|
|
432
|
-
|
|
519
|
+
assertApprovalGatedToolsHaveStorage(approvalGatedByAgent, memoryBuilder);
|
|
520
|
+
|
|
521
|
+
log.info("agents ready", { ids, defaultAgentId });
|
|
522
|
+
return { agents, defaultAgentId, ambientTools };
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Tool ids on `tools` that are approval-gated (`requireApproval: true`).
|
|
527
|
+
* Keys are used as a fallback when a tool omits an explicit `id`.
|
|
528
|
+
*/
|
|
529
|
+
export function approvalGatedToolIds(tools: MastraTools): string[] {
|
|
530
|
+
if (!tools || typeof tools !== "object") return [];
|
|
531
|
+
const ids: string[] = [];
|
|
532
|
+
for (const [key, tool] of Object.entries(tools)) {
|
|
533
|
+
if (!isApprovalGatedTool(tool)) continue;
|
|
534
|
+
ids.push(resolveToolId(tool, key));
|
|
535
|
+
}
|
|
536
|
+
return ids;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/** True when a Mastra / AI SDK tool pauses for human approval before execute. */
|
|
540
|
+
function isApprovalGatedTool(tool: unknown): boolean {
|
|
541
|
+
if (!tool || typeof tool !== "object") return false;
|
|
542
|
+
return (tool as { requireApproval?: boolean }).requireApproval === true;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function resolveToolId(tool: unknown, fallbackKey: string): string {
|
|
546
|
+
if (tool && typeof tool === "object" && typeof (tool as { id?: string }).id === "string") {
|
|
547
|
+
return (tool as { id: string }).id;
|
|
548
|
+
}
|
|
549
|
+
return fallbackKey;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Approval-gated tools suspend the agent loop until a human approves.
|
|
554
|
+
* Mastra persists those suspended runs in Mastra-instance-level storage
|
|
555
|
+
* (`memoryBuilder.instanceStorage()`), not per-agent memory - so boot
|
|
556
|
+
* must fail fast when such a tool is registered without storage.
|
|
557
|
+
*/
|
|
558
|
+
function assertApprovalGatedToolsHaveStorage(
|
|
559
|
+
gated: Array<{ agentId: string; toolIds: string[] }>,
|
|
560
|
+
memoryBuilder: MemoryBuilder | undefined,
|
|
561
|
+
): void {
|
|
562
|
+
if (gated.length === 0) return;
|
|
563
|
+
if (memoryBuilder?.instanceStorage()) return;
|
|
564
|
+
|
|
565
|
+
const detail = gated
|
|
566
|
+
.map(({ agentId, toolIds }) => `${agentId}: ${toolIds.join(", ")}`)
|
|
567
|
+
.join("; ");
|
|
568
|
+
throw new Error(
|
|
569
|
+
"mastra: approval-gated tools require plugin storage (PostgresStore) to persist suspended runs. " +
|
|
570
|
+
`Affected agents/tools: ${detail}. ` +
|
|
571
|
+
"Register lakebase() before mastra() so storage auto-enables, or pass storage: true explicitly.",
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Best-effort description of the *static* default model an agent will
|
|
577
|
+
* resolve to at call time. Walks the same precedence ladder as
|
|
578
|
+
* {@link resolveModel} / {@link buildModel}:
|
|
579
|
+
*
|
|
580
|
+
* 1. Per-agent `def.model` (string sugar -> the literal id;
|
|
581
|
+
* function / `DynamicArgument` -> `"<dynamic>"` because the
|
|
582
|
+
* resolver decides at call time).
|
|
583
|
+
* 2. Plugin-level `config.defaultModel` (same rules).
|
|
584
|
+
* 3. `DATABRICKS_SERVING_ENDPOINT_NAME` env var.
|
|
585
|
+
* 4. First entry of `config.defaultModelFallbacks ?? fallback.FALLBACK_MODEL_IDS`.
|
|
586
|
+
*
|
|
587
|
+
* Used for the startup `agent registered` log so operators can see
|
|
588
|
+
* which endpoint each agent points at by default. Per-request
|
|
589
|
+
* overrides (`X-Mastra-Model` etc.) and the workspace-catalogue
|
|
590
|
+
* fuzzy match are still applied at runtime.
|
|
591
|
+
*/
|
|
592
|
+
function describeAgentDefaultModel(config: MastraPluginConfig, def: MastraAgentDefinition): string {
|
|
593
|
+
const effective = def.model ?? config.defaultModel;
|
|
594
|
+
if (typeof effective === "string") return effective;
|
|
595
|
+
if (effective !== undefined) return "<dynamic>";
|
|
596
|
+
return (
|
|
597
|
+
process.env.DATABRICKS_SERVING_ENDPOINT_NAME ??
|
|
598
|
+
config.defaultModelFallbacks?.[0] ??
|
|
599
|
+
fallback.FALLBACK_MODEL_IDS[0]!
|
|
600
|
+
);
|
|
433
601
|
}
|
|
434
602
|
|
|
435
603
|
/**
|
|
@@ -446,9 +614,7 @@ export async function buildAgents(opts: {
|
|
|
446
614
|
* Omitted or empty inputs fall back to a single built-in analyst so
|
|
447
615
|
* the bare `mastra()` call still mounts a working chat route.
|
|
448
616
|
*/
|
|
449
|
-
function resolveDefinitions(
|
|
450
|
-
config: MastraPluginConfig,
|
|
451
|
-
): Record<string, MastraAgentDefinition> {
|
|
617
|
+
function resolveDefinitions(config: MastraPluginConfig): Record<string, MastraAgentDefinition> {
|
|
452
618
|
const input = config.agents;
|
|
453
619
|
if (!input) return fallbackDefinitions();
|
|
454
620
|
|
|
@@ -484,7 +650,7 @@ function resolveDefinitions(
|
|
|
484
650
|
/** Derive a registry id from a definition's `name`, with a fallback. */
|
|
485
651
|
function deriveAgentKey(def: MastraAgentDefinition, index?: number): string {
|
|
486
652
|
if (def.name) {
|
|
487
|
-
const slug =
|
|
653
|
+
const slug = string.toIdentifier(def.name);
|
|
488
654
|
if (slug) return slug;
|
|
489
655
|
}
|
|
490
656
|
return index === undefined ? FALLBACK_AGENT_ID : `agent_${index}`;
|
|
@@ -548,6 +714,13 @@ async function resolveTools(
|
|
|
548
714
|
return { ...ambientTools, ...resolved };
|
|
549
715
|
}
|
|
550
716
|
|
|
717
|
+
function resolveAgentWorkspace(
|
|
718
|
+
workspace: MastraAgentDefinition["workspace"],
|
|
719
|
+
): Workspace | undefined {
|
|
720
|
+
if (!workspace) return undefined;
|
|
721
|
+
return typeof workspace === "function" ? workspace() : workspace;
|
|
722
|
+
}
|
|
723
|
+
|
|
551
724
|
/**
|
|
552
725
|
* Build the {@link MastraPlugins} runtime proxy handed to
|
|
553
726
|
* `tools(plugins)` callbacks.
|
|
@@ -569,14 +742,15 @@ async function resolveTools(
|
|
|
569
742
|
* time instead of staring at a spinner for the full Genie round-trip.
|
|
570
743
|
*/
|
|
571
744
|
function buildPluginsMap(
|
|
572
|
-
|
|
745
|
+
config: MastraPluginConfig,
|
|
746
|
+
context: plugin.PluginContextLike | undefined,
|
|
573
747
|
): MastraPlugins {
|
|
574
748
|
const cache = new Map<string, MastraPluginToolkitProvider | null>();
|
|
575
749
|
return new Proxy({} as MastraPlugins, {
|
|
576
750
|
get(_target, propName) {
|
|
577
751
|
if (typeof propName !== "string") return undefined;
|
|
578
752
|
if (cache.has(propName)) return cache.get(propName) ?? undefined;
|
|
579
|
-
const provider = resolveProvider(context, propName);
|
|
753
|
+
const provider = resolveProvider(config, context, propName);
|
|
580
754
|
cache.set(propName, provider);
|
|
581
755
|
return provider ?? undefined;
|
|
582
756
|
},
|
|
@@ -585,18 +759,35 @@ function buildPluginsMap(
|
|
|
585
759
|
|
|
586
760
|
/**
|
|
587
761
|
* Pick the right {@link MastraPluginToolkitProvider} for a sibling
|
|
588
|
-
* plugin lookup. Returns the
|
|
589
|
-
* caller asks for `genie
|
|
590
|
-
*
|
|
762
|
+
* plugin lookup. Returns the Genie agent-backed adapter when
|
|
763
|
+
* the caller asks for `genie` AND at least one space is reachable
|
|
764
|
+
* via {@link resolveGenieSpaces} (the explicit
|
|
765
|
+
* `config.genieSpaces`, the registered AppKit `genie()` plugin's
|
|
766
|
+
* `spaces` config, or the `DATABRICKS_GENIE_SPACE_ID` env var).
|
|
767
|
+
* Falls back to the generic AppKit `ToolProvider` adapter for
|
|
768
|
+
* every other plugin name. `config` is threaded through so the
|
|
769
|
+
* Genie agent inherits the same model resolver / fallback
|
|
770
|
+
* ladder the calling agents use.
|
|
771
|
+
*
|
|
772
|
+
* The Genie agent talks to Genie directly via `@dbx-tools/genie`
|
|
773
|
+
* (`genieEventChat`) and the workspace
|
|
774
|
+
* `statementExecution.getStatement` API. AppKit's stock `genie`
|
|
775
|
+
* plugin is honored only for its resource manifest and `spaces`
|
|
776
|
+
* config so existing `app.yaml` configs and `genie({ spaces })`
|
|
777
|
+
* wiring keep working without change.
|
|
591
778
|
*/
|
|
592
779
|
function resolveProvider(
|
|
593
|
-
|
|
780
|
+
config: MastraPluginConfig,
|
|
781
|
+
context: plugin.PluginContextLike | undefined,
|
|
594
782
|
propName: string,
|
|
595
783
|
): MastraPluginToolkitProvider | null {
|
|
596
784
|
if (propName === "genie") {
|
|
597
|
-
const
|
|
598
|
-
if (
|
|
599
|
-
return
|
|
785
|
+
const spaces = resolveGenieSpaces(config, context);
|
|
786
|
+
if (Object.keys(spaces).length === 0) return null;
|
|
787
|
+
return buildGenieToolkitProvider({
|
|
788
|
+
spaces,
|
|
789
|
+
config,
|
|
790
|
+
}) as MastraPluginToolkitProvider;
|
|
600
791
|
}
|
|
601
792
|
const plugin = context?.getPlugins().get(propName);
|
|
602
793
|
return adaptPluginToolkit(plugin);
|
|
@@ -609,11 +800,7 @@ function resolveProvider(
|
|
|
609
800
|
*/
|
|
610
801
|
interface AppKitToolkitProvider {
|
|
611
802
|
toolkit?: (opts?: ToolkitOptions) => Record<string, AppKitToolkitEntry>;
|
|
612
|
-
executeAgentTool?: (
|
|
613
|
-
name: string,
|
|
614
|
-
args: unknown,
|
|
615
|
-
signal?: AbortSignal,
|
|
616
|
-
) => Promise<unknown>;
|
|
803
|
+
executeAgentTool?: (name: string, args: unknown, signal?: AbortSignal) => Promise<unknown>;
|
|
617
804
|
}
|
|
618
805
|
|
|
619
806
|
/** Single entry returned by an AppKit plugin's `.toolkit(opts)` call. */
|
|
@@ -658,17 +845,13 @@ function adaptPluginToolkit(plugin: unknown): MastraPluginToolkitProvider | null
|
|
|
658
845
|
* Schema parameters pass through unchanged - Mastra's `PublicSchema`
|
|
659
846
|
* accepts `JSONSchema7` directly via `@mastra/schema-compat`.
|
|
660
847
|
*/
|
|
661
|
-
function toolkitEntryToMastraTool(
|
|
662
|
-
entry: AppKitToolkitEntry,
|
|
663
|
-
plugin: AppKitToolkitProvider,
|
|
664
|
-
): Tool {
|
|
848
|
+
function toolkitEntryToMastraTool(entry: AppKitToolkitEntry, plugin: AppKitToolkitProvider): Tool {
|
|
665
849
|
return createTool({
|
|
666
850
|
id: `${entry.pluginName}__${entry.localName}`,
|
|
667
851
|
description: entry.def.description,
|
|
668
852
|
...(entry.def.parameters ? { inputSchema: entry.def.parameters as never } : {}),
|
|
669
853
|
execute: async (input: unknown, context: unknown) => {
|
|
670
|
-
const signal = (context as { abortSignal?: AbortSignal } | undefined)
|
|
671
|
-
?.abortSignal;
|
|
854
|
+
const signal = (context as { abortSignal?: AbortSignal } | undefined)?.abortSignal;
|
|
672
855
|
return plugin.executeAgentTool!(entry.localName, input, signal);
|
|
673
856
|
},
|
|
674
857
|
});
|