@dbx-tools/appkit-mastra 0.1.12 → 0.1.14
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 +303 -637
- package/index.ts +46 -38
- package/package.json +58 -43
- package/src/agents.ts +224 -66
- package/src/chart.ts +531 -429
- package/src/config.ts +270 -19
- package/src/filesystems.ts +1090 -0
- package/src/genie.ts +1000 -660
- package/src/history.ts +166 -79
- package/src/mcp.ts +105 -0
- package/src/memory.ts +119 -81
- package/src/mlflow.ts +149 -0
- package/src/model.ts +75 -408
- package/src/observability.ts +144 -0
- package/src/pagination.ts +34 -0
- package/src/plugin.ts +566 -59
- package/src/processors.ts +168 -0
- package/src/rest.ts +67 -0
- package/src/server.ts +232 -45
- package/src/serving-sanitize.ts +167 -0
- package/src/serving.ts +27 -243
- 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 -20
- package/dist/index.js +0 -20
- package/dist/src/agents.d.ts +0 -306
- package/dist/src/agents.js +0 -403
- package/dist/src/chart.d.ts +0 -170
- package/dist/src/chart.js +0 -491
- package/dist/src/config.d.ts +0 -183
- package/dist/src/config.js +0 -12
- package/dist/src/genie.d.ts +0 -131
- package/dist/src/genie.js +0 -630
- package/dist/src/history.d.ts +0 -67
- package/dist/src/history.js +0 -172
- package/dist/src/memory.d.ts +0 -79
- package/dist/src/memory.js +0 -210
- package/dist/src/model.d.ts +0 -159
- package/dist/src/model.js +0 -427
- package/dist/src/plugin.d.ts +0 -130
- package/dist/src/plugin.js +0 -261
- package/dist/src/processors/strip-stale-charts.d.ts +0 -29
- package/dist/src/processors/strip-stale-charts.js +0 -96
- package/dist/src/server.d.ts +0 -46
- package/dist/src/server.js +0 -123
- package/dist/src/serving.d.ts +0 -156
- package/dist/src/serving.js +0 -231
- package/dist/src/tools/email.d.ts +0 -74
- package/dist/src/tools/email.js +0 -122
- package/dist/tsconfig.build.tsbuildinfo +0 -1
- package/src/processors/strip-stale-charts.ts +0 -105
- package/src/tools/email.ts +0 -147
package/dist/src/agents.js
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent registration for the Mastra AppKit plugin.
|
|
3
|
-
*
|
|
4
|
-
* Mirrors the shape of the AppKit `agents` plugin (`config.agents` map
|
|
5
|
-
* of {@link MastraAgentDefinition}, dual-form `tools` accepting a plain
|
|
6
|
-
* record or a `(plugins) => tools` callback). Resolves each definition
|
|
7
|
-
* into a Mastra `Agent` instance during plugin setup; user-supplied
|
|
8
|
-
* tool callbacks are invoked exactly once with a typed
|
|
9
|
-
* {@link MastraPlugins} map built from registered sibling plugins.
|
|
10
|
-
*
|
|
11
|
-
* When no agents are registered the plugin falls back to a single
|
|
12
|
-
* built-in analyst so the bare `mastra()` call still mounts a working
|
|
13
|
-
* `chatRoute` agent for demos.
|
|
14
|
-
*/
|
|
15
|
-
import { genie } from "@databricks/appkit";
|
|
16
|
-
import { logUtils, pluginUtils, stringUtils } from "@dbx-tools/appkit-shared";
|
|
17
|
-
import { Agent } from "@mastra/core/agent";
|
|
18
|
-
import { createTool } from "@mastra/core/tools";
|
|
19
|
-
import { buildRenderDataTool } from "./chart.js";
|
|
20
|
-
import { buildGenieProvider } from "./genie.js";
|
|
21
|
-
import { buildModel } from "./model.js";
|
|
22
|
-
import { stripStaleChartsProcessor } from "./processors/strip-stale-charts.js";
|
|
23
|
-
/** Re-export of Mastra's native `createTool` for full-feature access. */
|
|
24
|
-
export { createTool } from "@mastra/core/tools";
|
|
25
|
-
/**
|
|
26
|
-
* AppKit-shaped tool factory. Lets users mix-and-match tools across
|
|
27
|
-
* AppKit's `agents` plugin and `mastra` with a single import:
|
|
28
|
-
*
|
|
29
|
-
* ```ts
|
|
30
|
-
* import { tool } from "@dbx-tools/appkit-mastra";
|
|
31
|
-
* import { z } from "zod";
|
|
32
|
-
*
|
|
33
|
-
* get_weather: tool({
|
|
34
|
-
* description: "Weather",
|
|
35
|
-
* schema: z.object({ city: z.string() }),
|
|
36
|
-
* execute: async ({ city }) => `Sunny in ${city}`,
|
|
37
|
-
* }),
|
|
38
|
-
* ```
|
|
39
|
-
*
|
|
40
|
-
* Maps onto Mastra's `createTool`:
|
|
41
|
-
*
|
|
42
|
-
* - `description` -> `description` (required)
|
|
43
|
-
* - `schema` -> `inputSchema` (optional)
|
|
44
|
-
* - `execute(input)` -> `execute(input, ctx)` - Mastra already calls
|
|
45
|
-
* the first arg with the parsed inputs, so the body shape is
|
|
46
|
-
* identical. The Mastra `context` arg is forwarded as the second
|
|
47
|
-
* parameter when the caller declares it.
|
|
48
|
-
* - `id`: optional. Defaults to a stable identifier derived from
|
|
49
|
-
* `description` (slugified, with a short hash suffix for
|
|
50
|
-
* uniqueness). Pass an explicit `id` when you need a stable string
|
|
51
|
-
* for tracing or MCP exposure.
|
|
52
|
-
*
|
|
53
|
-
* Reach for {@link createTool} when you need Mastra-only fields
|
|
54
|
-
* (`outputSchema`, `suspendSchema`, `requireApproval`, `mcp`, etc.).
|
|
55
|
-
*/
|
|
56
|
-
export function tool(opts) {
|
|
57
|
-
const id = opts.id ?? deriveToolId(opts.description);
|
|
58
|
-
return createTool({
|
|
59
|
-
id,
|
|
60
|
-
description: opts.description,
|
|
61
|
-
...(opts.schema ? { inputSchema: opts.schema } : {}),
|
|
62
|
-
execute: opts.execute,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Build a deterministic Mastra tool id from a description.
|
|
67
|
-
* Delegates to {@link stringUtils.toUniqueSlug}: slug + always-on
|
|
68
|
-
* 6-char FNV-1a base-32 suffix so two tools with the same leading
|
|
69
|
-
* words don't collide in traces. Stable across runs.
|
|
70
|
-
*/
|
|
71
|
-
function deriveToolId(description) {
|
|
72
|
-
return stringUtils.toUniqueSlug(description, { fallbackPrefix: "tool" });
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Identity helper that brands a definition as a Mastra agent. Mirrors
|
|
76
|
-
* AppKit's `createAgent(def)` so the registration shape matches:
|
|
77
|
-
*
|
|
78
|
-
* ```ts
|
|
79
|
-
* const support = createAgent({
|
|
80
|
-
* instructions: "...",
|
|
81
|
-
* model: "databricks-claude-sonnet-4-6",
|
|
82
|
-
* tools(plugins) { return { ... }; },
|
|
83
|
-
* });
|
|
84
|
-
* ```
|
|
85
|
-
*
|
|
86
|
-
* Returns the definition unchanged - the wrapper exists only to anchor
|
|
87
|
-
* type inference and to match the AppKit API surface.
|
|
88
|
-
*/
|
|
89
|
-
export function createAgent(def) {
|
|
90
|
-
return def;
|
|
91
|
-
}
|
|
92
|
-
/** Fallback agent id used when `config.agents` is omitted entirely. */
|
|
93
|
-
export const FALLBACK_AGENT_ID = "default";
|
|
94
|
-
const FALLBACK_AGENT_INSTRUCTIONS = `You are a data analyst. The user will ask questions about
|
|
95
|
-
business metrics and may share personal preferences you should remember across turns.
|
|
96
|
-
|
|
97
|
-
Rules:
|
|
98
|
-
|
|
99
|
-
1. Quote numbers exactly. Never invent data.
|
|
100
|
-
2. When the user states a preference or durable fact about themselves
|
|
101
|
-
("I'm in EU so use EUR", "always show me the SQL"), acknowledge that
|
|
102
|
-
you will remember it.
|
|
103
|
-
3. If you don't have enough information to answer, ask a clarifying
|
|
104
|
-
question instead of guessing.`;
|
|
105
|
-
/**
|
|
106
|
-
* Style guardrails appended to every agent's `instructions` to curb
|
|
107
|
-
* common LLM-isms (em dashes, emojis, sycophantic openers, excessive
|
|
108
|
-
* hedging, throwaway closers). Appended rather than prepended so the
|
|
109
|
-
* agent's role/context comes first; the model's recency bias then
|
|
110
|
-
* helps the style rules dominate the response surface.
|
|
111
|
-
*
|
|
112
|
-
* Override globally via {@link MastraPluginConfig.styleInstructions}
|
|
113
|
-
* (pass `false` to disable entirely, or a string to replace).
|
|
114
|
-
*/
|
|
115
|
-
export const DEFAULT_STYLE_INSTRUCTIONS = [
|
|
116
|
-
"Output style:",
|
|
117
|
-
"",
|
|
118
|
-
"Use markdown formatting, including headings, lists, and code blocks.",
|
|
119
|
-
"Avoid lists and headers for short replies.",
|
|
120
|
-
"Plain prose.",
|
|
121
|
-
"Use hyphens (-) only. Never use em dashes or en dashes.",
|
|
122
|
-
"Never use emojis.",
|
|
123
|
-
"Skip openers like 'Great question', 'Absolutely', and 'I'd be happy to help'.",
|
|
124
|
-
"Skip closers like 'Let me know if you have any questions'.",
|
|
125
|
-
"Skip self-disclaimers like 'I should mention' and 'It's important to note'.",
|
|
126
|
-
"Answer directly.",
|
|
127
|
-
"Do not include a preamble before the actual answer.",
|
|
128
|
-
"Use lists and headers only when they clarify a multi-part answer.",
|
|
129
|
-
].join("\n");
|
|
130
|
-
/**
|
|
131
|
-
* Resolve the style block to append to every agent's instructions.
|
|
132
|
-
* Returns `null` when the caller opted out (`styleInstructions: false`).
|
|
133
|
-
*/
|
|
134
|
-
function resolveStyleInstructions(config) {
|
|
135
|
-
if (config.styleInstructions === false)
|
|
136
|
-
return null;
|
|
137
|
-
if (typeof config.styleInstructions === "string") {
|
|
138
|
-
return config.styleInstructions;
|
|
139
|
-
}
|
|
140
|
-
return DEFAULT_STYLE_INSTRUCTIONS;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Join an agent's bespoke instructions with the resolved style block.
|
|
144
|
-
* Returns the bespoke text unchanged when the style block is disabled.
|
|
145
|
-
*/
|
|
146
|
-
function composeInstructions(agentInstructions, style) {
|
|
147
|
-
if (!style)
|
|
148
|
-
return agentInstructions;
|
|
149
|
-
return `${agentInstructions.trimEnd()}\n\n${style}`;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Resolve every entry in `config.agents` into a Mastra `Agent`
|
|
153
|
-
* instance. When `config.agents` is omitted the plugin registers a
|
|
154
|
-
* single built-in `default` analyst so the bare `mastra()` call still
|
|
155
|
-
* yields a working agent.
|
|
156
|
-
*
|
|
157
|
-
* Per-agent tool callbacks are invoked once with a typed
|
|
158
|
-
* {@link MastraPlugins} index built from registered sibling plugins
|
|
159
|
-
* (currently `genie`; extend `MastraPlugins` to surface more).
|
|
160
|
-
*
|
|
161
|
-
* @throws when `config.defaultAgent` is set to an id that isn't in the
|
|
162
|
-
* resolved registry; this is a wiring bug, not a runtime condition.
|
|
163
|
-
*/
|
|
164
|
-
export async function buildAgents(opts) {
|
|
165
|
-
const { config, context, memoryBuilder, log } = opts;
|
|
166
|
-
const definitions = resolveDefinitions(config);
|
|
167
|
-
const ids = Object.keys(definitions);
|
|
168
|
-
const defaultAgentId = config.defaultAgent ?? ids[0] ?? FALLBACK_AGENT_ID;
|
|
169
|
-
const plugins = buildPluginsMap(config, context);
|
|
170
|
-
// System-default ambient tools every agent gets out of the box.
|
|
171
|
-
// Currently just `render_data` for inline visualizations; the
|
|
172
|
-
// user can shadow it by including a same-named tool in their own
|
|
173
|
-
// `config.tools` or per-agent `tools`. Order in {@link resolveTools}
|
|
174
|
-
// is `system -> user-ambient -> per-agent`, last write wins.
|
|
175
|
-
const systemTools = {
|
|
176
|
-
render_data: buildRenderDataTool(config),
|
|
177
|
-
};
|
|
178
|
-
const ambientTools = { ...systemTools, ...(config.tools ?? {}) };
|
|
179
|
-
const style = resolveStyleInstructions(config);
|
|
180
|
-
// Default-on protection against the model copying turn-scoped
|
|
181
|
-
// chartIds from prior assistant tool results into the new
|
|
182
|
-
// turn's `[[chart:<id>]]` markers. Opt out per-plugin via
|
|
183
|
-
// `config.stripStaleCharts: false`.
|
|
184
|
-
const inputProcessors = config.stripStaleCharts === false ? [] : [stripStaleChartsProcessor];
|
|
185
|
-
const agents = {};
|
|
186
|
-
for (const [id, def] of Object.entries(definitions)) {
|
|
187
|
-
const tools = await resolveTools(def.tools, plugins, ambientTools);
|
|
188
|
-
const memory = memoryBuilder?.forAgent(id, def);
|
|
189
|
-
agents[id] = new Agent({
|
|
190
|
-
id,
|
|
191
|
-
name: def.name ?? id,
|
|
192
|
-
...(def.description !== undefined ? { description: def.description } : {}),
|
|
193
|
-
instructions: composeInstructions(def.instructions, style),
|
|
194
|
-
model: resolveModel(config, def.model),
|
|
195
|
-
tools,
|
|
196
|
-
...(memory ? { memory } : {}),
|
|
197
|
-
...(inputProcessors.length > 0 ? { inputProcessors } : {}),
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
if (!agents[defaultAgentId]) {
|
|
201
|
-
throw new Error(`mastra: defaultAgent "${defaultAgentId}" not found in registered agents (${ids.join(", ") || "none"})`);
|
|
202
|
-
}
|
|
203
|
-
log.info("agents registered", { ids, defaultAgentId });
|
|
204
|
-
return { agents, defaultAgentId };
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Normalize `config.agents` into a `Record<id, definition>`. Accepts
|
|
208
|
-
* any of the three shapes documented on
|
|
209
|
-
* {@link MastraPluginConfig.agents}:
|
|
210
|
-
*
|
|
211
|
-
* - Record - returned as-is when non-empty.
|
|
212
|
-
* - Single definition (detected via the required `instructions`
|
|
213
|
-
* field) - keyed by `slugify(def.name)` or `FALLBACK_AGENT_ID`.
|
|
214
|
-
* - Array - keyed by `slugify(def.name)` or `agent_${i}`; duplicate
|
|
215
|
-
* slugs fail loudly so users know to set explicit names.
|
|
216
|
-
*
|
|
217
|
-
* Omitted or empty inputs fall back to a single built-in analyst so
|
|
218
|
-
* the bare `mastra()` call still mounts a working chat route.
|
|
219
|
-
*/
|
|
220
|
-
function resolveDefinitions(config) {
|
|
221
|
-
const input = config.agents;
|
|
222
|
-
if (!input)
|
|
223
|
-
return fallbackDefinitions();
|
|
224
|
-
if (Array.isArray(input)) {
|
|
225
|
-
if (input.length === 0)
|
|
226
|
-
return fallbackDefinitions();
|
|
227
|
-
const out = {};
|
|
228
|
-
input.forEach((def, i) => {
|
|
229
|
-
const key = deriveAgentKey(def, i);
|
|
230
|
-
if (out[key]) {
|
|
231
|
-
throw new Error(`mastra: duplicate agent id "${key}" derived from name "${def.name ?? ""}"; ` +
|
|
232
|
-
`set unique \`name\`s on each definition`);
|
|
233
|
-
}
|
|
234
|
-
out[key] = def;
|
|
235
|
-
});
|
|
236
|
-
return out;
|
|
237
|
-
}
|
|
238
|
-
// Single-definition shorthand: an agent always has `instructions: string`,
|
|
239
|
-
// a record-of-agents never has that field directly.
|
|
240
|
-
if (typeof input.instructions === "string") {
|
|
241
|
-
const def = input;
|
|
242
|
-
const key = deriveAgentKey(def);
|
|
243
|
-
return { [key]: def };
|
|
244
|
-
}
|
|
245
|
-
const record = input;
|
|
246
|
-
if (Object.keys(record).length === 0)
|
|
247
|
-
return fallbackDefinitions();
|
|
248
|
-
return record;
|
|
249
|
-
}
|
|
250
|
-
/** Derive a registry id from a definition's `name`, with a fallback. */
|
|
251
|
-
function deriveAgentKey(def, index) {
|
|
252
|
-
if (def.name) {
|
|
253
|
-
const slug = stringUtils.toIdentifier(def.name);
|
|
254
|
-
if (slug)
|
|
255
|
-
return slug;
|
|
256
|
-
}
|
|
257
|
-
return index === undefined ? FALLBACK_AGENT_ID : `agent_${index}`;
|
|
258
|
-
}
|
|
259
|
-
/** Built-in fallback registry used when `agents` is omitted / empty. */
|
|
260
|
-
function fallbackDefinitions() {
|
|
261
|
-
return {
|
|
262
|
-
[FALLBACK_AGENT_ID]: {
|
|
263
|
-
name: "Default Agent",
|
|
264
|
-
instructions: FALLBACK_AGENT_INSTRUCTIONS,
|
|
265
|
-
},
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Pick the effective model spec for an agent. Fallback ladder, in
|
|
270
|
-
* order:
|
|
271
|
-
*
|
|
272
|
-
* 1. Per-agent `def.model` (string sugar or `DynamicArgument`).
|
|
273
|
-
* 2. Plugin-level `config.defaultModel` (string sugar or
|
|
274
|
-
* `DynamicArgument`) - mirrors AppKit's `agents({ defaultModel })`.
|
|
275
|
-
* 3. The auto-resolver that mints user-scoped tokens against
|
|
276
|
-
* `/serving-endpoints` via {@link buildModel}.
|
|
277
|
-
*
|
|
278
|
-
* String values are treated as `modelId` sugar and threaded through
|
|
279
|
-
* `buildModel`'s override hook so the runtime fuzzy matcher and the
|
|
280
|
-
* per-request `X-Mastra-Model` override layer on top of the static
|
|
281
|
-
* choice. Non-string `DynamicArgument`s are passed through verbatim;
|
|
282
|
-
* callers that need full control over `providerId` / `headers` /
|
|
283
|
-
* `modelId` bypass the resolver pipeline entirely.
|
|
284
|
-
*/
|
|
285
|
-
function resolveModel(config, override) {
|
|
286
|
-
const effective = override ?? config.defaultModel;
|
|
287
|
-
if (effective === undefined) {
|
|
288
|
-
return ({ requestContext }) => buildModel(config, requestContext);
|
|
289
|
-
}
|
|
290
|
-
if (typeof effective === "string") {
|
|
291
|
-
const modelId = effective;
|
|
292
|
-
return ({ requestContext }) => buildModel(config, requestContext, { modelId });
|
|
293
|
-
}
|
|
294
|
-
return effective;
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Resolve a definition's `tools` field to a flat `MastraTools` record,
|
|
298
|
-
* merging in plugin-level ambient tools (per-agent tools win on key
|
|
299
|
-
* collision). Callback errors propagate verbatim so the original stack
|
|
300
|
-
* survives - the caller already knows which agent was registering.
|
|
301
|
-
*/
|
|
302
|
-
async function resolveTools(defTools, plugins, ambientTools) {
|
|
303
|
-
if (!defTools)
|
|
304
|
-
return { ...ambientTools };
|
|
305
|
-
const resolved = typeof defTools === "function" ? await defTools(plugins) : defTools;
|
|
306
|
-
return { ...ambientTools, ...resolved };
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Build the {@link MastraPlugins} runtime proxy handed to
|
|
310
|
-
* `tools(plugins)` callbacks.
|
|
311
|
-
*
|
|
312
|
-
* Implemented as a `Proxy` over the AppKit plugin context so
|
|
313
|
-
* `plugins.<name>` resolves at first access. Any sibling plugin that
|
|
314
|
-
* implements AppKit's standard `ToolProvider` interface
|
|
315
|
-
* (`toolkit(opts?)` + `executeAgentTool(name, args, signal?)`) is
|
|
316
|
-
* auto-adapted into Mastra tools. Unknown names return `undefined`,
|
|
317
|
-
* matching AppKit's `Plugins` semantics so `plugins.foo?.toolkit()`
|
|
318
|
-
* remains safe in environments where `foo` isn't registered.
|
|
319
|
-
*
|
|
320
|
-
* `genie` is special-cased to swap the generic AppKit toolkit (which
|
|
321
|
-
* runs `executeAgentTool` and only emits a single final `tool-result`
|
|
322
|
-
* chunk per call) for the streaming-aware tools built by
|
|
323
|
-
* {@link buildGenieProvider}. The streaming variant forwards each
|
|
324
|
-
* Genie wire event (status, SQL, row counts, errors) out through the
|
|
325
|
-
* Mastra `ctx.writer`, so the UI gets `tool-output` chunks in real
|
|
326
|
-
* time instead of staring at a spinner for the full Genie round-trip.
|
|
327
|
-
*/
|
|
328
|
-
function buildPluginsMap(config, context) {
|
|
329
|
-
const cache = new Map();
|
|
330
|
-
return new Proxy({}, {
|
|
331
|
-
get(_target, propName) {
|
|
332
|
-
if (typeof propName !== "string")
|
|
333
|
-
return undefined;
|
|
334
|
-
if (cache.has(propName))
|
|
335
|
-
return cache.get(propName) ?? undefined;
|
|
336
|
-
const provider = resolveProvider(config, context, propName);
|
|
337
|
-
cache.set(propName, provider);
|
|
338
|
-
return provider ?? undefined;
|
|
339
|
-
},
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Pick the right {@link MastraPluginToolkitProvider} for a sibling
|
|
344
|
-
* plugin lookup. Returns the streaming-aware Genie adapter when the
|
|
345
|
-
* caller asks for `genie`; falls back to the generic AppKit
|
|
346
|
-
* `ToolProvider` adapter for every other plugin name. `config` is
|
|
347
|
-
* threaded through so Genie's tool can run the chart planner
|
|
348
|
-
* inline against the same model resolver / fallback ladder the
|
|
349
|
-
* agents use.
|
|
350
|
-
*/
|
|
351
|
-
function resolveProvider(config, context, propName) {
|
|
352
|
-
if (propName === "genie") {
|
|
353
|
-
const geniePlugin = pluginUtils.instance(context, genie);
|
|
354
|
-
if (!geniePlugin)
|
|
355
|
-
return null;
|
|
356
|
-
return buildGenieProvider(geniePlugin, { config });
|
|
357
|
-
}
|
|
358
|
-
const plugin = context?.getPlugins().get(propName);
|
|
359
|
-
return adaptPluginToolkit(plugin);
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Adapt an AppKit `ToolProvider` plugin instance into a
|
|
363
|
-
* {@link MastraPluginToolkitProvider}. Returns `null` for any plugin
|
|
364
|
-
* that doesn't implement both `toolkit` and `executeAgentTool` (e.g.
|
|
365
|
-
* `server`, `lakebase` when used only as a Postgres pool, etc.).
|
|
366
|
-
*/
|
|
367
|
-
function adaptPluginToolkit(plugin) {
|
|
368
|
-
if (!plugin || typeof plugin !== "object")
|
|
369
|
-
return null;
|
|
370
|
-
const p = plugin;
|
|
371
|
-
if (typeof p.toolkit !== "function" || typeof p.executeAgentTool !== "function") {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
return {
|
|
375
|
-
toolkit(opts) {
|
|
376
|
-
const entries = p.toolkit(opts);
|
|
377
|
-
const tools = {};
|
|
378
|
-
for (const [key, entry] of Object.entries(entries)) {
|
|
379
|
-
tools[key] = toolkitEntryToMastraTool(entry, p);
|
|
380
|
-
}
|
|
381
|
-
return tools;
|
|
382
|
-
},
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Wrap a single {@link AppKitToolkitEntry} as a Mastra tool whose
|
|
387
|
-
* `execute` dispatches back through `plugin.executeAgentTool(...)` so
|
|
388
|
-
* AppKit's OBO auth (`asUser`) and telemetry spans stay intact. JSON
|
|
389
|
-
* Schema parameters pass through unchanged - Mastra's `PublicSchema`
|
|
390
|
-
* accepts `JSONSchema7` directly via `@mastra/schema-compat`.
|
|
391
|
-
*/
|
|
392
|
-
function toolkitEntryToMastraTool(entry, plugin) {
|
|
393
|
-
return createTool({
|
|
394
|
-
id: `${entry.pluginName}__${entry.localName}`,
|
|
395
|
-
description: entry.def.description,
|
|
396
|
-
...(entry.def.parameters ? { inputSchema: entry.def.parameters } : {}),
|
|
397
|
-
execute: async (input, context) => {
|
|
398
|
-
const signal = context
|
|
399
|
-
?.abortSignal;
|
|
400
|
-
return plugin.executeAgentTool(entry.localName, input, signal);
|
|
401
|
-
},
|
|
402
|
-
});
|
|
403
|
-
}
|
package/dist/src/chart.d.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chart-rendering primitives.
|
|
3
|
-
*
|
|
4
|
-
* Three surfaces, one shared brain:
|
|
5
|
-
*
|
|
6
|
-
* - {@link buildRenderDataTool}: a Mastra tool the model calls
|
|
7
|
-
* ("here is a dataset, render it as a chart"). The tool's
|
|
8
|
-
* `execute` emits a `kind: "chart"` event with the raw rows to
|
|
9
|
-
* `ctx.writer` synchronously, kicks off the chart-planner agent,
|
|
10
|
-
* and `await`s the planner promise before returning so the
|
|
11
|
-
* planner's latency is attributed to this tool's trace span.
|
|
12
|
-
* The LLM-bound output is just `{ chartId }`, so its context
|
|
13
|
-
* stays flat regardless of dataset size.
|
|
14
|
-
*
|
|
15
|
-
* - {@link emitChartWithPlanning}: the underlying helper that both
|
|
16
|
-
* `render_data` and Genie's `drainGenieStream` call. Mints the
|
|
17
|
-
* `chartId`, fires the dataset event immediately, runs the
|
|
18
|
-
* planner in the background, and returns `{ chartId,
|
|
19
|
-
* plannerPromise }` so callers can choose to await for trace
|
|
20
|
-
* shape or fire-and-forget.
|
|
21
|
-
*
|
|
22
|
-
* - {@link runChartPlanner}: the chart-planner Agent + ECOption
|
|
23
|
-
* expansion as a plain async function. Used internally by
|
|
24
|
-
* {@link emitChartWithPlanning}; producers shouldn't reach for
|
|
25
|
-
* it directly so chart events keep a single wire-format
|
|
26
|
-
* contract.
|
|
27
|
-
*
|
|
28
|
-
* The model wires the chart into its reply by emitting the marker
|
|
29
|
-
* `[[chart:<chartId>]]` on its own line in markdown. The chat
|
|
30
|
-
* client splits the assistant text on these markers and drops a
|
|
31
|
-
* `<ChartSlot>` in at the position the model placed it; the slot
|
|
32
|
-
* shows a skeleton until the second `kind: "chart"` event (with
|
|
33
|
-
* the resolved `EChartsOption`) arrives, then swaps in the
|
|
34
|
-
* rendered Echarts visualisation.
|
|
35
|
-
*/
|
|
36
|
-
import type { RequestContext } from "@mastra/core/request-context";
|
|
37
|
-
import { z } from "zod";
|
|
38
|
-
import type { MastraPluginConfig } from "./config.js";
|
|
39
|
-
/**
|
|
40
|
-
* Compact, model-friendly representation of an Echarts spec. The
|
|
41
|
-
* planner agent emits this; {@link planToEchartsOption} expands it
|
|
42
|
-
* into a real `EChartsOption` JSON. Two layers because letting the
|
|
43
|
-
* model fill in a fully-typed `EChartsOption` is brittle (hundreds
|
|
44
|
-
* of optional fields, deep unions, version-dependent shapes). A
|
|
45
|
-
* small "chart plan" schema is much more reliable for a fast model
|
|
46
|
-
* and keeps animation / tooltip / styling defaults consistent
|
|
47
|
-
* across charts.
|
|
48
|
-
*/
|
|
49
|
-
declare const chartPlanSchema: z.ZodObject<{
|
|
50
|
-
chartType: z.ZodEnum<{
|
|
51
|
-
bar: "bar";
|
|
52
|
-
line: "line";
|
|
53
|
-
area: "area";
|
|
54
|
-
scatter: "scatter";
|
|
55
|
-
pie: "pie";
|
|
56
|
-
}>;
|
|
57
|
-
title: z.ZodOptional<z.ZodString>;
|
|
58
|
-
xAxisLabel: z.ZodOptional<z.ZodString>;
|
|
59
|
-
yAxisLabel: z.ZodOptional<z.ZodString>;
|
|
60
|
-
categories: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
61
|
-
series: z.ZodArray<z.ZodObject<{
|
|
62
|
-
name: z.ZodString;
|
|
63
|
-
data: z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>, z.ZodObject<{
|
|
64
|
-
name: z.ZodString;
|
|
65
|
-
value: z.ZodNumber;
|
|
66
|
-
}, z.core.$strip>]>>;
|
|
67
|
-
}, z.core.$strip>>;
|
|
68
|
-
}, z.core.$strip>;
|
|
69
|
-
type ChartPlan = z.infer<typeof chartPlanSchema>;
|
|
70
|
-
/** Inputs to {@link runChartPlanner}. */
|
|
71
|
-
export interface RunChartPlannerOptions {
|
|
72
|
-
config: MastraPluginConfig;
|
|
73
|
-
requestContext?: RequestContext;
|
|
74
|
-
title: string;
|
|
75
|
-
description?: string;
|
|
76
|
-
data: ReadonlyArray<Record<string, unknown>>;
|
|
77
|
-
}
|
|
78
|
-
/** Output of {@link runChartPlanner}: a fully-formed Echarts spec. */
|
|
79
|
-
export interface RunChartPlannerResult {
|
|
80
|
-
option: Record<string, unknown>;
|
|
81
|
-
chartType: ChartPlan["chartType"];
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Run the chart planner against the given dataset and return a
|
|
85
|
-
* full Echarts `EChartsOption` JSON. Used by
|
|
86
|
-
* {@link emitChartWithPlanning}; tools and producers shouldn't
|
|
87
|
-
* call this directly (use the helper instead so chart events
|
|
88
|
-
* follow the same wire-format contract everywhere).
|
|
89
|
-
*/
|
|
90
|
-
export declare function runChartPlanner(opts: RunChartPlannerOptions): Promise<RunChartPlannerResult>;
|
|
91
|
-
/**
|
|
92
|
-
* Minimal `ToolStream`-shaped writer surface. Defined locally so
|
|
93
|
-
* helpers can take any object with a `.write` method without
|
|
94
|
-
* importing Mastra's full `ToolStream` (which would also drag in
|
|
95
|
-
* agent / tool types this module doesn't otherwise need).
|
|
96
|
-
*/
|
|
97
|
-
interface MinimalWriter {
|
|
98
|
-
write: (chunk: unknown) => unknown;
|
|
99
|
-
}
|
|
100
|
-
/** Inputs to {@link emitChartWithPlanning}. */
|
|
101
|
-
export interface EmitChartWithPlanningOptions {
|
|
102
|
-
/** Mastra `ctx.writer`; missing or closed writers are tolerated. */
|
|
103
|
-
writer?: MinimalWriter;
|
|
104
|
-
/** Plugin config; used to resolve the planner's model. */
|
|
105
|
-
config: MastraPluginConfig;
|
|
106
|
-
/** Per-request context (OBO auth). */
|
|
107
|
-
requestContext?: RequestContext;
|
|
108
|
-
/** Title shown above the rendered chart. Required. */
|
|
109
|
-
title: string;
|
|
110
|
-
/** Optional one-line intent biasing the planner. */
|
|
111
|
-
description?: string;
|
|
112
|
-
/** Tabular dataset to chart (one object per row). */
|
|
113
|
-
data: ReadonlyArray<Record<string, unknown>>;
|
|
114
|
-
}
|
|
115
|
-
/** Output of {@link emitChartWithPlanning}. */
|
|
116
|
-
export interface EmitChartWithPlanningResult {
|
|
117
|
-
/** Short id matching the marker `[[chart:<chartId>]]`. */
|
|
118
|
-
chartId: string;
|
|
119
|
-
/**
|
|
120
|
-
* Promise that resolves once the planner has finished and the
|
|
121
|
-
* `kind: "chart"` event with the option has been emitted (or
|
|
122
|
-
* once the planner has failed silently). Callers that want
|
|
123
|
-
* trace observability should `await` this before returning
|
|
124
|
-
* from their tool's `execute`; callers that want pure
|
|
125
|
-
* fire-and-forget can ignore it.
|
|
126
|
-
*/
|
|
127
|
-
plannerPromise: Promise<void>;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Shared chart-emission primitive used by both the `render_data`
|
|
131
|
-
* tool and Genie's `drainGenieStream`. Keeps both producers on
|
|
132
|
-
* one wire-format contract so the chat client only ever has to
|
|
133
|
-
* understand a single chart event shape.
|
|
134
|
-
*
|
|
135
|
-
* Behaviour:
|
|
136
|
-
*
|
|
137
|
-
* 1. Generates a short `chartId` (8 hex chars).
|
|
138
|
-
* 2. Immediately emits `{ kind: "chart", chartId, title,
|
|
139
|
-
* description?, data }` via the writer so the chat client can
|
|
140
|
-
* mount its `<ChartSlot>` with the rows in hand.
|
|
141
|
-
* 3. Kicks off the chart-planner agent in the background. On
|
|
142
|
-
* success, emits a second `{ kind: "chart", chartId, option }`
|
|
143
|
-
* event - same `chartId`, just the spec - so the client merges
|
|
144
|
-
* the two into one rendered chart. On failure, no follow-up
|
|
145
|
-
* event fires; the client falls back to whatever it can do
|
|
146
|
-
* with the dataset alone (typically a "render failed" frame
|
|
147
|
-
* after the parent tool finishes).
|
|
148
|
-
*
|
|
149
|
-
* Returns `chartId` synchronously so the caller can include it in
|
|
150
|
-
* the tool result (model uses it in `[[chart:<chartId>]]`
|
|
151
|
-
* markers), and `plannerPromise` so the caller can choose
|
|
152
|
-
* trace-spanning vs. snappy-return semantics.
|
|
153
|
-
*/
|
|
154
|
-
export declare function emitChartWithPlanning(opts: EmitChartWithPlanningOptions): Promise<EmitChartWithPlanningResult>;
|
|
155
|
-
/**
|
|
156
|
-
* Build the `render_data` tool bound to the given plugin config.
|
|
157
|
-
*
|
|
158
|
-
* The tool is a thin wrapper around {@link emitChartWithPlanning}:
|
|
159
|
-
* a single `kind: "chart"` writer event ships the raw rows to
|
|
160
|
-
* the client immediately, the chart-planner agent runs alongside
|
|
161
|
-
* (so the calling LLM stays unblocked while the planner thinks),
|
|
162
|
-
* and a follow-up `kind: "chart"` event with the resolved
|
|
163
|
-
* `EChartsOption` lands when it's ready. The tool's `execute`
|
|
164
|
-
* awaits the planner promise so the planner work shows up under
|
|
165
|
-
* the tool's trace span; the LLM still gets back just
|
|
166
|
-
* `{ chartId }`, so its context stays small regardless of dataset
|
|
167
|
-
* size.
|
|
168
|
-
*/
|
|
169
|
-
export declare function buildRenderDataTool(config: MastraPluginConfig): import("@mastra/core/tools").Tool<any, any, any, any, import("@mastra/core/tools").ToolExecutionContext<any, any, unknown>, "render_data", unknown>;
|
|
170
|
-
export {};
|