@dbx-tools/appkit-mastra 0.1.5 → 0.1.10
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 +394 -0
- package/index.ts +46 -37
- package/package.json +58 -47
- package/src/agents.ts +233 -62
- package/src/chart.ts +555 -285
- package/src/config.ts +282 -18
- package/src/filesystems.ts +1090 -0
- package/src/genie.ts +1004 -601
- package/src/history.ts +178 -79
- 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 +573 -59
- package/src/processors.ts +168 -0
- package/src/rest.ts +67 -0
- package/src/server.ts +243 -45
- 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 -19
- package/dist/index.js +0 -19
- package/dist/src/agents.d.ts +0 -306
- package/dist/src/agents.js +0 -393
- package/dist/src/chart.d.ts +0 -104
- package/dist/src/chart.js +0 -375
- package/dist/src/config.d.ts +0 -170
- package/dist/src/config.js +0 -12
- package/dist/src/genie.d.ts +0 -116
- package/dist/src/genie.js +0 -594
- package/dist/src/history.d.ts +0 -67
- package/dist/src/history.js +0 -158
- 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 -130
- package/dist/src/plugin.js +0 -255
- package/dist/src/render-chart-route.d.ts +0 -33
- package/dist/src/render-chart-route.js +0 -120
- package/dist/src/server.d.ts +0 -46
- package/dist/src/server.js +0 -113
- package/dist/src/serving.d.ts +0 -156
- package/dist/src/serving.js +0 -214
- package/src/render-chart-route.ts +0 -141
package/src/agents.ts
CHANGED
|
@@ -10,22 +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 { buildRenderDataTool } from "./chart
|
|
25
|
-
import type { MastraPluginConfig } from "./config
|
|
26
|
-
import {
|
|
27
|
-
import type { MemoryBuilder } from "./memory
|
|
28
|
-
import { buildModel } from "./model
|
|
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";
|
|
29
34
|
|
|
30
35
|
/**
|
|
31
36
|
* Tool record accepted by every Mastra `Agent.tools` field and by the
|
|
@@ -121,12 +126,12 @@ export interface AppKitToolOptions {
|
|
|
121
126
|
|
|
122
127
|
/**
|
|
123
128
|
* Build a deterministic Mastra tool id from a description.
|
|
124
|
-
* Delegates to {@link
|
|
125
|
-
*
|
|
126
|
-
* 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.
|
|
127
132
|
*/
|
|
128
133
|
function deriveToolId(description: string): string {
|
|
129
|
-
return
|
|
134
|
+
return string.toUniqueSlug(description, { fallbackPrefix: "tool" });
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
/**
|
|
@@ -145,7 +150,8 @@ function deriveToolId(description: string): string {
|
|
|
145
150
|
* type inference and to match the AppKit API surface.
|
|
146
151
|
*/
|
|
147
152
|
export function createAgent<T extends MastraAgentDefinition>(def: T): T {
|
|
148
|
-
|
|
153
|
+
const workspace = def.workspace ?? createWorkspace();
|
|
154
|
+
return { ...def, workspace };
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
/**
|
|
@@ -218,15 +224,16 @@ export interface MastraPluginToolkitProvider {
|
|
|
218
224
|
export type MastraPlugins = Record<string, MastraPluginToolkitProvider>;
|
|
219
225
|
|
|
220
226
|
/** Function form of {@link MastraAgentDefinition.tools}. */
|
|
221
|
-
export type MastraToolsFn = (
|
|
222
|
-
|
|
223
|
-
|
|
227
|
+
export type MastraToolsFn = (plugins: MastraPlugins) => MastraTools | Promise<MastraTools>;
|
|
228
|
+
|
|
229
|
+
/** Function form of {@link MastraAgentDefinition.workspace}. */
|
|
230
|
+
export type MastraAgentWorkspaceResolver = () => Workspace | undefined;
|
|
224
231
|
|
|
225
232
|
/**
|
|
226
233
|
* A code-defined Mastra agent. Mirrors the shape AppKit's `agents`
|
|
227
234
|
* plugin uses for `AgentDefinition`. The registry key under
|
|
228
|
-
* `config.agents` is
|
|
229
|
-
* informational (defaults to the key).
|
|
235
|
+
* `config.agents` is the `agentId` the client streams against; `name`
|
|
236
|
+
* is purely informational (defaults to the key).
|
|
230
237
|
*/
|
|
231
238
|
export interface MastraAgentDefinition {
|
|
232
239
|
/** Display name used as `Agent.name`. Defaults to the registry key. */
|
|
@@ -275,7 +282,7 @@ export interface MastraAgentDefinition {
|
|
|
275
282
|
*
|
|
276
283
|
* - `undefined` (default): inherit `config.storage`. When that's
|
|
277
284
|
* enabled, the agent gets its **own per-agent `PostgresStore`**
|
|
278
|
-
* keyed by
|
|
285
|
+
* keyed by {@link agentStorageSchemaName} so threads and
|
|
279
286
|
* messages stay isolated between agents in the same database.
|
|
280
287
|
* - `false`: disable storage for this agent only (purely in-memory).
|
|
281
288
|
* - `true`: enable with the per-agent default schema.
|
|
@@ -283,6 +290,12 @@ export interface MastraAgentDefinition {
|
|
|
283
290
|
* `PostgresStore` config (custom schema, connection, etc.).
|
|
284
291
|
*/
|
|
285
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;
|
|
286
299
|
}
|
|
287
300
|
|
|
288
301
|
/**
|
|
@@ -291,19 +304,16 @@ export interface MastraAgentDefinition {
|
|
|
291
304
|
* strip `id`. The built-in `Omit` collapses unions to one shape with
|
|
292
305
|
* common fields only, which loses the connection-style discriminants.
|
|
293
306
|
*/
|
|
294
|
-
type DistributiveOmit<T, K extends keyof never> = T extends unknown
|
|
295
|
-
? Omit<T, K>
|
|
296
|
-
: never;
|
|
307
|
+
type DistributiveOmit<T, K extends keyof never> = T extends unknown ? Omit<T, K> : never;
|
|
297
308
|
|
|
298
309
|
/**
|
|
299
310
|
* `PostgresStoreConfig` minus `id` - per-agent overrides accept any
|
|
300
311
|
* Mastra-supported storage shape. `id` is filled in automatically
|
|
301
312
|
* from the agent registry key so traces stay stable.
|
|
302
313
|
*/
|
|
303
|
-
export type MastraStorageConfigOverride = DistributiveOmit<
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
> & { id?: string };
|
|
314
|
+
export type MastraStorageConfigOverride = DistributiveOmit<PostgresStoreConfig, "id"> & {
|
|
315
|
+
id?: string;
|
|
316
|
+
};
|
|
307
317
|
|
|
308
318
|
/**
|
|
309
319
|
* `PgVectorConfig` minus `id` - per-agent overrides accept any
|
|
@@ -318,11 +328,28 @@ export type MastraMemoryConfigOverride = DistributiveOmit<PgVectorConfig, "id">
|
|
|
318
328
|
export interface BuiltAgents {
|
|
319
329
|
agents: Record<string, Agent>;
|
|
320
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;
|
|
321
337
|
}
|
|
322
338
|
|
|
323
339
|
/** Fallback agent id used when `config.agents` is omitted entirely. */
|
|
324
340
|
export const FALLBACK_AGENT_ID = "default";
|
|
325
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
|
+
|
|
326
353
|
const FALLBACK_AGENT_INSTRUCTIONS = `You are a data analyst. The user will ask questions about
|
|
327
354
|
business metrics and may share personal preferences you should remember across turns.
|
|
328
355
|
|
|
@@ -383,6 +410,16 @@ function composeInstructions(agentInstructions: string, style: string | null): s
|
|
|
383
410
|
return `${agentInstructions.trimEnd()}\n\n${style}`;
|
|
384
411
|
}
|
|
385
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
|
+
|
|
386
423
|
/**
|
|
387
424
|
* Resolve every entry in `config.agents` into a Mastra `Agent`
|
|
388
425
|
* instance. When `config.agents` is omitted the plugin registers a
|
|
@@ -398,39 +435,78 @@ function composeInstructions(agentInstructions: string, style: string | null): s
|
|
|
398
435
|
*/
|
|
399
436
|
export async function buildAgents(opts: {
|
|
400
437
|
config: MastraPluginConfig;
|
|
401
|
-
context:
|
|
438
|
+
context: plugin.PluginContextLike | undefined;
|
|
402
439
|
memoryBuilder?: MemoryBuilder;
|
|
403
|
-
log:
|
|
440
|
+
log: log.Logger;
|
|
404
441
|
}): Promise<BuiltAgents> {
|
|
405
442
|
const { config, context, memoryBuilder, log } = opts;
|
|
406
443
|
const definitions = resolveDefinitions(config);
|
|
407
444
|
const ids = Object.keys(definitions);
|
|
408
445
|
const defaultAgentId = config.defaultAgent ?? ids[0] ?? FALLBACK_AGENT_ID;
|
|
409
446
|
|
|
410
|
-
const plugins = buildPluginsMap(context);
|
|
411
|
-
// System-default ambient tools every agent gets out of the box
|
|
412
|
-
//
|
|
413
|
-
//
|
|
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
|
|
414
452
|
// `config.tools` or per-agent `tools`. Order in {@link resolveTools}
|
|
415
453
|
// is `system -> user-ambient -> per-agent`, last write wins.
|
|
416
454
|
const systemTools: MastraTools = {
|
|
417
455
|
render_data: buildRenderDataTool(config),
|
|
456
|
+
summarize: buildSummarizeTool(config),
|
|
457
|
+
};
|
|
458
|
+
const ambientTools = {
|
|
459
|
+
...systemTools,
|
|
460
|
+
...(config.tools ?? {}),
|
|
418
461
|
};
|
|
419
|
-
const ambientTools = { ...systemTools, ...(config.tools ?? {}) };
|
|
420
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
|
+
];
|
|
421
471
|
const agents: Record<string, Agent> = {};
|
|
472
|
+
const approvalGatedByAgent: Array<{ agentId: string; toolIds: string[] }> = [];
|
|
422
473
|
|
|
423
474
|
for (const [id, def] of Object.entries(definitions)) {
|
|
424
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 });
|
|
425
479
|
const memory = memoryBuilder?.forAgent(id, def);
|
|
426
480
|
agents[id] = new Agent({
|
|
427
481
|
id,
|
|
428
482
|
name: def.name ?? id,
|
|
429
|
-
|
|
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),
|
|
430
488
|
instructions: composeInstructions(def.instructions, style),
|
|
431
489
|
model: resolveModel(config, def.model),
|
|
490
|
+
defaultOptions: {
|
|
491
|
+
maxSteps: config.agentMaxSteps ?? DEFAULT_AGENT_MAX_STEPS,
|
|
492
|
+
},
|
|
432
493
|
tools,
|
|
433
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),
|
|
434
510
|
});
|
|
435
511
|
}
|
|
436
512
|
|
|
@@ -440,8 +516,88 @@ export async function buildAgents(opts: {
|
|
|
440
516
|
);
|
|
441
517
|
}
|
|
442
518
|
|
|
443
|
-
|
|
444
|
-
|
|
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
|
+
);
|
|
445
601
|
}
|
|
446
602
|
|
|
447
603
|
/**
|
|
@@ -458,9 +614,7 @@ export async function buildAgents(opts: {
|
|
|
458
614
|
* Omitted or empty inputs fall back to a single built-in analyst so
|
|
459
615
|
* the bare `mastra()` call still mounts a working chat route.
|
|
460
616
|
*/
|
|
461
|
-
function resolveDefinitions(
|
|
462
|
-
config: MastraPluginConfig,
|
|
463
|
-
): Record<string, MastraAgentDefinition> {
|
|
617
|
+
function resolveDefinitions(config: MastraPluginConfig): Record<string, MastraAgentDefinition> {
|
|
464
618
|
const input = config.agents;
|
|
465
619
|
if (!input) return fallbackDefinitions();
|
|
466
620
|
|
|
@@ -496,7 +650,7 @@ function resolveDefinitions(
|
|
|
496
650
|
/** Derive a registry id from a definition's `name`, with a fallback. */
|
|
497
651
|
function deriveAgentKey(def: MastraAgentDefinition, index?: number): string {
|
|
498
652
|
if (def.name) {
|
|
499
|
-
const slug =
|
|
653
|
+
const slug = string.toIdentifier(def.name);
|
|
500
654
|
if (slug) return slug;
|
|
501
655
|
}
|
|
502
656
|
return index === undefined ? FALLBACK_AGENT_ID : `agent_${index}`;
|
|
@@ -560,6 +714,13 @@ async function resolveTools(
|
|
|
560
714
|
return { ...ambientTools, ...resolved };
|
|
561
715
|
}
|
|
562
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
|
+
|
|
563
724
|
/**
|
|
564
725
|
* Build the {@link MastraPlugins} runtime proxy handed to
|
|
565
726
|
* `tools(plugins)` callbacks.
|
|
@@ -581,14 +742,15 @@ async function resolveTools(
|
|
|
581
742
|
* time instead of staring at a spinner for the full Genie round-trip.
|
|
582
743
|
*/
|
|
583
744
|
function buildPluginsMap(
|
|
584
|
-
|
|
745
|
+
config: MastraPluginConfig,
|
|
746
|
+
context: plugin.PluginContextLike | undefined,
|
|
585
747
|
): MastraPlugins {
|
|
586
748
|
const cache = new Map<string, MastraPluginToolkitProvider | null>();
|
|
587
749
|
return new Proxy({} as MastraPlugins, {
|
|
588
750
|
get(_target, propName) {
|
|
589
751
|
if (typeof propName !== "string") return undefined;
|
|
590
752
|
if (cache.has(propName)) return cache.get(propName) ?? undefined;
|
|
591
|
-
const provider = resolveProvider(context, propName);
|
|
753
|
+
const provider = resolveProvider(config, context, propName);
|
|
592
754
|
cache.set(propName, provider);
|
|
593
755
|
return provider ?? undefined;
|
|
594
756
|
},
|
|
@@ -597,18 +759,35 @@ function buildPluginsMap(
|
|
|
597
759
|
|
|
598
760
|
/**
|
|
599
761
|
* Pick the right {@link MastraPluginToolkitProvider} for a sibling
|
|
600
|
-
* plugin lookup. Returns the
|
|
601
|
-
* caller asks for `genie
|
|
602
|
-
*
|
|
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.
|
|
603
778
|
*/
|
|
604
779
|
function resolveProvider(
|
|
605
|
-
|
|
780
|
+
config: MastraPluginConfig,
|
|
781
|
+
context: plugin.PluginContextLike | undefined,
|
|
606
782
|
propName: string,
|
|
607
783
|
): MastraPluginToolkitProvider | null {
|
|
608
784
|
if (propName === "genie") {
|
|
609
|
-
const
|
|
610
|
-
if (
|
|
611
|
-
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;
|
|
612
791
|
}
|
|
613
792
|
const plugin = context?.getPlugins().get(propName);
|
|
614
793
|
return adaptPluginToolkit(plugin);
|
|
@@ -621,11 +800,7 @@ function resolveProvider(
|
|
|
621
800
|
*/
|
|
622
801
|
interface AppKitToolkitProvider {
|
|
623
802
|
toolkit?: (opts?: ToolkitOptions) => Record<string, AppKitToolkitEntry>;
|
|
624
|
-
executeAgentTool?: (
|
|
625
|
-
name: string,
|
|
626
|
-
args: unknown,
|
|
627
|
-
signal?: AbortSignal,
|
|
628
|
-
) => Promise<unknown>;
|
|
803
|
+
executeAgentTool?: (name: string, args: unknown, signal?: AbortSignal) => Promise<unknown>;
|
|
629
804
|
}
|
|
630
805
|
|
|
631
806
|
/** Single entry returned by an AppKit plugin's `.toolkit(opts)` call. */
|
|
@@ -670,17 +845,13 @@ function adaptPluginToolkit(plugin: unknown): MastraPluginToolkitProvider | null
|
|
|
670
845
|
* Schema parameters pass through unchanged - Mastra's `PublicSchema`
|
|
671
846
|
* accepts `JSONSchema7` directly via `@mastra/schema-compat`.
|
|
672
847
|
*/
|
|
673
|
-
function toolkitEntryToMastraTool(
|
|
674
|
-
entry: AppKitToolkitEntry,
|
|
675
|
-
plugin: AppKitToolkitProvider,
|
|
676
|
-
): Tool {
|
|
848
|
+
function toolkitEntryToMastraTool(entry: AppKitToolkitEntry, plugin: AppKitToolkitProvider): Tool {
|
|
677
849
|
return createTool({
|
|
678
850
|
id: `${entry.pluginName}__${entry.localName}`,
|
|
679
851
|
description: entry.def.description,
|
|
680
852
|
...(entry.def.parameters ? { inputSchema: entry.def.parameters as never } : {}),
|
|
681
853
|
execute: async (input: unknown, context: unknown) => {
|
|
682
|
-
const signal = (context as { abortSignal?: AbortSignal } | undefined)
|
|
683
|
-
?.abortSignal;
|
|
854
|
+
const signal = (context as { abortSignal?: AbortSignal } | undefined)?.abortSignal;
|
|
684
855
|
return plugin.executeAgentTool!(entry.localName, input, signal);
|
|
685
856
|
},
|
|
686
857
|
});
|