@dbx-tools/appkit-mastra 0.1.58 → 0.1.67

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.
Files changed (44) hide show
  1. package/README.md +41 -1
  2. package/dist/index.d.ts +1229 -17
  3. package/dist/index.js +3348 -19
  4. package/package.json +17 -28
  5. package/src/agents.ts +7 -1
  6. package/src/config.ts +64 -0
  7. package/src/genie.ts +9 -21
  8. package/{index.ts → src/index.ts} +7 -9
  9. package/src/mcp.ts +89 -0
  10. package/src/model.ts +9 -3
  11. package/src/plugin.ts +51 -8
  12. package/src/serving.ts +5 -9
  13. package/src/statement.ts +8 -36
  14. package/dist/src/agents.d.ts +0 -316
  15. package/dist/src/agents.js +0 -470
  16. package/dist/src/chart.d.ts +0 -153
  17. package/dist/src/chart.js +0 -570
  18. package/dist/src/config.d.ts +0 -295
  19. package/dist/src/config.js +0 -55
  20. package/dist/src/genie.d.ts +0 -161
  21. package/dist/src/genie.js +0 -973
  22. package/dist/src/history.d.ts +0 -95
  23. package/dist/src/history.js +0 -278
  24. package/dist/src/memory.d.ts +0 -109
  25. package/dist/src/memory.js +0 -253
  26. package/dist/src/model.d.ts +0 -52
  27. package/dist/src/model.js +0 -198
  28. package/dist/src/observability.d.ts +0 -64
  29. package/dist/src/observability.js +0 -83
  30. package/dist/src/plugin.d.ts +0 -177
  31. package/dist/src/plugin.js +0 -554
  32. package/dist/src/processor.d.ts +0 -8
  33. package/dist/src/processor.js +0 -40
  34. package/dist/src/processors/strip-stale-charts.d.ts +0 -32
  35. package/dist/src/processors/strip-stale-charts.js +0 -98
  36. package/dist/src/server.d.ts +0 -51
  37. package/dist/src/server.js +0 -152
  38. package/dist/src/serving.d.ts +0 -65
  39. package/dist/src/serving.js +0 -79
  40. package/dist/src/statement.d.ts +0 -66
  41. package/dist/src/statement.js +0 -111
  42. package/dist/src/writer.d.ts +0 -23
  43. package/dist/src/writer.js +0 -37
  44. package/dist/tsconfig.build.tsbuildinfo +0 -1
@@ -1,470 +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
- * streamable agent for demos.
14
- */
15
- import { appkitUtils, logUtils, stringUtils } from "@dbx-tools/shared";
16
- import { Agent } from "@mastra/core/agent";
17
- import { createTool } from "@mastra/core/tools";
18
- import { buildRenderDataTool } from "./chart.js";
19
- import { buildGenieToolkitProvider, resolveGenieSpaces } from "./genie.js";
20
- import { buildModel, FALLBACK_MODEL_IDS } from "./model.js";
21
- import { ResultProcessor } from "./processor.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
- /**
95
- * Default per-turn step ceiling applied to every registered agent
96
- * when {@link MastraPluginConfig.agentMaxSteps} is unset. Sized to
97
- * fit a decomposed Genie turn (grounding + several `ask_genie`
98
- * calls + `prepare_chart` per dataset + the final-text reply) with
99
- * headroom for the model to chain a couple of follow-ups before
100
- * answering - well above Mastra's own `agent.generate` default of
101
- * 5, which would cut multi-step orchestration off mid-loop.
102
- */
103
- export const DEFAULT_AGENT_MAX_STEPS = 25;
104
- const FALLBACK_AGENT_INSTRUCTIONS = `You are a data analyst. The user will ask questions about
105
- business metrics and may share personal preferences you should remember across turns.
106
-
107
- Rules:
108
-
109
- 1. Quote numbers exactly. Never invent data.
110
- 2. When the user states a preference or durable fact about themselves
111
- ("I'm in EU so use EUR", "always show me the SQL"), acknowledge that
112
- you will remember it.
113
- 3. If you don't have enough information to answer, ask a clarifying
114
- question instead of guessing.`;
115
- /**
116
- * Style guardrails appended to every agent's `instructions` to curb
117
- * common LLM-isms (em dashes, emojis, sycophantic openers, excessive
118
- * hedging, throwaway closers). Appended rather than prepended so the
119
- * agent's role/context comes first; the model's recency bias then
120
- * helps the style rules dominate the response surface.
121
- *
122
- * Override globally via {@link MastraPluginConfig.styleInstructions}
123
- * (pass `false` to disable entirely, or a string to replace).
124
- */
125
- export const DEFAULT_STYLE_INSTRUCTIONS = [
126
- "Output style:",
127
- "",
128
- "Use markdown formatting, including headings, lists, and code blocks.",
129
- "Avoid lists and headers for short replies.",
130
- "Plain prose.",
131
- "Use hyphens (-) only. Never use em dashes or en dashes.",
132
- "Never use emojis.",
133
- "Skip openers like 'Great question', 'Absolutely', and 'I'd be happy to help'.",
134
- "Skip closers like 'Let me know if you have any questions'.",
135
- "Skip self-disclaimers like 'I should mention' and 'It's important to note'.",
136
- "Answer directly.",
137
- "Do not include a preamble before the actual answer.",
138
- "Use lists and headers only when they clarify a multi-part answer.",
139
- ].join("\n");
140
- /**
141
- * Resolve the style block to append to every agent's instructions.
142
- * Returns `null` when the caller opted out (`styleInstructions: false`).
143
- */
144
- function resolveStyleInstructions(config) {
145
- if (config.styleInstructions === false)
146
- return null;
147
- if (typeof config.styleInstructions === "string") {
148
- return config.styleInstructions;
149
- }
150
- return DEFAULT_STYLE_INSTRUCTIONS;
151
- }
152
- /**
153
- * Join an agent's bespoke instructions with the resolved style block.
154
- * Returns the bespoke text unchanged when the style block is disabled.
155
- */
156
- function composeInstructions(agentInstructions, style) {
157
- if (!style)
158
- return agentInstructions;
159
- return `${agentInstructions.trimEnd()}\n\n${style}`;
160
- }
161
- /**
162
- * Resolve every entry in `config.agents` into a Mastra `Agent`
163
- * instance. When `config.agents` is omitted the plugin registers a
164
- * single built-in `default` analyst so the bare `mastra()` call still
165
- * yields a working agent.
166
- *
167
- * Per-agent tool callbacks are invoked once with a typed
168
- * {@link MastraPlugins} index built from registered sibling plugins
169
- * (currently `genie`; extend `MastraPlugins` to surface more).
170
- *
171
- * @throws when `config.defaultAgent` is set to an id that isn't in the
172
- * resolved registry; this is a wiring bug, not a runtime condition.
173
- */
174
- export async function buildAgents(opts) {
175
- const { config, context, memoryBuilder, log } = opts;
176
- const definitions = resolveDefinitions(config);
177
- const ids = Object.keys(definitions);
178
- const defaultAgentId = config.defaultAgent ?? ids[0] ?? FALLBACK_AGENT_ID;
179
- const plugins = buildPluginsMap(config, context);
180
- // System-default ambient tools every agent gets out of the box.
181
- // Currently just `render_data` for inline visualizations; the
182
- // user can shadow it by including a same-named tool in their own
183
- // `config.tools` or per-agent `tools`. Order in {@link resolveTools}
184
- // is `system -> user-ambient -> per-agent`, last write wins.
185
- const systemTools = {
186
- render_data: buildRenderDataTool(config),
187
- };
188
- const ambientTools = { ...systemTools, ...(config.tools ?? {}) };
189
- const style = resolveStyleInstructions(config);
190
- // Default-on protection against the model copying turn-scoped
191
- // chartIds from prior assistant tool results into the new
192
- // turn's `[chart:<id>]` markers. Opt out per-plugin via
193
- // `config.stripStaleCharts: false`.
194
- const outputProcessors = [new ResultProcessor()];
195
- const inputProcessors = config.stripStaleCharts === false ? [] : [stripStaleChartsProcessor];
196
- const agents = {};
197
- for (const [id, def] of Object.entries(definitions)) {
198
- const tools = await resolveTools(def.tools, plugins, ambientTools);
199
- const memory = memoryBuilder?.forAgent(id, def);
200
- agents[id] = new Agent({
201
- id,
202
- name: def.name ?? id,
203
- ...(def.description !== undefined ? { description: def.description } : {}),
204
- instructions: composeInstructions(def.instructions, style),
205
- model: resolveModel(config, def.model),
206
- defaultOptions: {
207
- maxSteps: config.agentMaxSteps ?? DEFAULT_AGENT_MAX_STEPS,
208
- },
209
- tools,
210
- ...(memory ? { memory } : {}),
211
- inputProcessors,
212
- outputProcessors,
213
- });
214
- // Surface the effective default model per agent so operators can
215
- // see at a glance which endpoint each agent points at without
216
- // having to fire a request and inspect a trace. The value is the
217
- // *static* default; per-request overrides (header / query /
218
- // body) and the workspace-catalogue fuzzy match still apply at
219
- // call time.
220
- log.info("agent registered", {
221
- id,
222
- name: def.name ?? id,
223
- defaultModel: describeAgentDefaultModel(config, def),
224
- tools: Object.keys(tools),
225
- });
226
- }
227
- if (!agents[defaultAgentId]) {
228
- throw new Error(`mastra: defaultAgent "${defaultAgentId}" not found in registered agents (${ids.join(", ") || "none"})`);
229
- }
230
- log.info("agents ready", { ids, defaultAgentId });
231
- return { agents, defaultAgentId };
232
- }
233
- /**
234
- * Best-effort description of the *static* default model an agent will
235
- * resolve to at call time. Walks the same precedence ladder as
236
- * {@link resolveModel} / {@link buildModel}:
237
- *
238
- * 1. Per-agent `def.model` (string sugar -> the literal id;
239
- * function / `DynamicArgument` -> `"<dynamic>"` because the
240
- * resolver decides at call time).
241
- * 2. Plugin-level `config.defaultModel` (same rules).
242
- * 3. `DATABRICKS_SERVING_ENDPOINT_NAME` env var.
243
- * 4. First entry of `config.defaultModelFallbacks ?? FALLBACK_MODEL_IDS`.
244
- *
245
- * Used for the startup `agent registered` log so operators can see
246
- * which endpoint each agent points at by default. Per-request
247
- * overrides (`X-Mastra-Model` etc.) and the workspace-catalogue
248
- * fuzzy match are still applied at runtime.
249
- */
250
- function describeAgentDefaultModel(config, def) {
251
- const effective = def.model ?? config.defaultModel;
252
- if (typeof effective === "string")
253
- return effective;
254
- if (effective !== undefined)
255
- return "<dynamic>";
256
- return (process.env.DATABRICKS_SERVING_ENDPOINT_NAME ??
257
- config.defaultModelFallbacks?.[0] ??
258
- FALLBACK_MODEL_IDS[0]);
259
- }
260
- /**
261
- * Normalize `config.agents` into a `Record<id, definition>`. Accepts
262
- * any of the three shapes documented on
263
- * {@link MastraPluginConfig.agents}:
264
- *
265
- * - Record - returned as-is when non-empty.
266
- * - Single definition (detected via the required `instructions`
267
- * field) - keyed by `slugify(def.name)` or `FALLBACK_AGENT_ID`.
268
- * - Array - keyed by `slugify(def.name)` or `agent_${i}`; duplicate
269
- * slugs fail loudly so users know to set explicit names.
270
- *
271
- * Omitted or empty inputs fall back to a single built-in analyst so
272
- * the bare `mastra()` call still mounts a working chat route.
273
- */
274
- function resolveDefinitions(config) {
275
- const input = config.agents;
276
- if (!input)
277
- return fallbackDefinitions();
278
- if (Array.isArray(input)) {
279
- if (input.length === 0)
280
- return fallbackDefinitions();
281
- const out = {};
282
- input.forEach((def, i) => {
283
- const key = deriveAgentKey(def, i);
284
- if (out[key]) {
285
- throw new Error(`mastra: duplicate agent id "${key}" derived from name "${def.name ?? ""}"; ` +
286
- `set unique \`name\`s on each definition`);
287
- }
288
- out[key] = def;
289
- });
290
- return out;
291
- }
292
- // Single-definition shorthand: an agent always has `instructions: string`,
293
- // a record-of-agents never has that field directly.
294
- if (typeof input.instructions === "string") {
295
- const def = input;
296
- const key = deriveAgentKey(def);
297
- return { [key]: def };
298
- }
299
- const record = input;
300
- if (Object.keys(record).length === 0)
301
- return fallbackDefinitions();
302
- return record;
303
- }
304
- /** Derive a registry id from a definition's `name`, with a fallback. */
305
- function deriveAgentKey(def, index) {
306
- if (def.name) {
307
- const slug = stringUtils.toIdentifier(def.name);
308
- if (slug)
309
- return slug;
310
- }
311
- return index === undefined ? FALLBACK_AGENT_ID : `agent_${index}`;
312
- }
313
- /** Built-in fallback registry used when `agents` is omitted / empty. */
314
- function fallbackDefinitions() {
315
- return {
316
- [FALLBACK_AGENT_ID]: {
317
- name: "Default Agent",
318
- instructions: FALLBACK_AGENT_INSTRUCTIONS,
319
- },
320
- };
321
- }
322
- /**
323
- * Pick the effective model spec for an agent. Fallback ladder, in
324
- * order:
325
- *
326
- * 1. Per-agent `def.model` (string sugar or `DynamicArgument`).
327
- * 2. Plugin-level `config.defaultModel` (string sugar or
328
- * `DynamicArgument`) - mirrors AppKit's `agents({ defaultModel })`.
329
- * 3. The auto-resolver that mints user-scoped tokens against
330
- * `/serving-endpoints` via {@link buildModel}.
331
- *
332
- * String values are treated as `modelId` sugar and threaded through
333
- * `buildModel`'s override hook so the runtime fuzzy matcher and the
334
- * per-request `X-Mastra-Model` override layer on top of the static
335
- * choice. Non-string `DynamicArgument`s are passed through verbatim;
336
- * callers that need full control over `providerId` / `headers` /
337
- * `modelId` bypass the resolver pipeline entirely.
338
- */
339
- function resolveModel(config, override) {
340
- const effective = override ?? config.defaultModel;
341
- if (effective === undefined) {
342
- return ({ requestContext }) => buildModel(config, requestContext);
343
- }
344
- if (typeof effective === "string") {
345
- const modelId = effective;
346
- return ({ requestContext }) => buildModel(config, requestContext, { modelId });
347
- }
348
- return effective;
349
- }
350
- /**
351
- * Resolve a definition's `tools` field to a flat `MastraTools` record,
352
- * merging in plugin-level ambient tools (per-agent tools win on key
353
- * collision). Callback errors propagate verbatim so the original stack
354
- * survives - the caller already knows which agent was registering.
355
- */
356
- async function resolveTools(defTools, plugins, ambientTools) {
357
- if (!defTools)
358
- return { ...ambientTools };
359
- const resolved = typeof defTools === "function" ? await defTools(plugins) : defTools;
360
- return { ...ambientTools, ...resolved };
361
- }
362
- /**
363
- * Build the {@link MastraPlugins} runtime proxy handed to
364
- * `tools(plugins)` callbacks.
365
- *
366
- * Implemented as a `Proxy` over the AppKit plugin context so
367
- * `plugins.<name>` resolves at first access. Any sibling plugin that
368
- * implements AppKit's standard `ToolProvider` interface
369
- * (`toolkit(opts?)` + `executeAgentTool(name, args, signal?)`) is
370
- * auto-adapted into Mastra tools. Unknown names return `undefined`,
371
- * matching AppKit's `Plugins` semantics so `plugins.foo?.toolkit()`
372
- * remains safe in environments where `foo` isn't registered.
373
- *
374
- * `genie` is special-cased to swap the generic AppKit toolkit (which
375
- * runs `executeAgentTool` and only emits a single final `tool-result`
376
- * chunk per call) for the streaming-aware tools built by
377
- * {@link buildGenieProvider}. The streaming variant forwards each
378
- * Genie wire event (status, SQL, row counts, errors) out through the
379
- * Mastra `ctx.writer`, so the UI gets `tool-output` chunks in real
380
- * time instead of staring at a spinner for the full Genie round-trip.
381
- */
382
- function buildPluginsMap(config, context) {
383
- const cache = new Map();
384
- return new Proxy({}, {
385
- get(_target, propName) {
386
- if (typeof propName !== "string")
387
- return undefined;
388
- if (cache.has(propName))
389
- return cache.get(propName) ?? undefined;
390
- const provider = resolveProvider(config, context, propName);
391
- cache.set(propName, provider);
392
- return provider ?? undefined;
393
- },
394
- });
395
- }
396
- /**
397
- * Pick the right {@link MastraPluginToolkitProvider} for a sibling
398
- * plugin lookup. Returns the Genie agent-backed adapter when
399
- * the caller asks for `genie` AND at least one space is reachable
400
- * via {@link resolveGenieSpaces} (the explicit
401
- * `config.genieSpaces`, the registered AppKit `genie()` plugin's
402
- * `spaces` config, or the `DATABRICKS_GENIE_SPACE_ID` env var).
403
- * Falls back to the generic AppKit `ToolProvider` adapter for
404
- * every other plugin name. `config` is threaded through so the
405
- * Genie agent inherits the same model resolver / fallback
406
- * ladder the calling agents use.
407
- *
408
- * The Genie agent talks to Genie directly via `@dbx-tools/genie`
409
- * (`genieEventChat`) and the workspace
410
- * `statementExecution.getStatement` API. AppKit's stock `genie`
411
- * plugin is honored only for its resource manifest and `spaces`
412
- * config so existing `app.yaml` configs and `genie({ spaces })`
413
- * wiring keep working without change.
414
- */
415
- function resolveProvider(config, context, propName) {
416
- if (propName === "genie") {
417
- const spaces = resolveGenieSpaces(config, context);
418
- if (Object.keys(spaces).length === 0)
419
- return null;
420
- return buildGenieToolkitProvider({
421
- spaces,
422
- config,
423
- });
424
- }
425
- const plugin = context?.getPlugins().get(propName);
426
- return adaptPluginToolkit(plugin);
427
- }
428
- /**
429
- * Adapt an AppKit `ToolProvider` plugin instance into a
430
- * {@link MastraPluginToolkitProvider}. Returns `null` for any plugin
431
- * that doesn't implement both `toolkit` and `executeAgentTool` (e.g.
432
- * `server`, `lakebase` when used only as a Postgres pool, etc.).
433
- */
434
- function adaptPluginToolkit(plugin) {
435
- if (!plugin || typeof plugin !== "object")
436
- return null;
437
- const p = plugin;
438
- if (typeof p.toolkit !== "function" || typeof p.executeAgentTool !== "function") {
439
- return null;
440
- }
441
- return {
442
- toolkit(opts) {
443
- const entries = p.toolkit(opts);
444
- const tools = {};
445
- for (const [key, entry] of Object.entries(entries)) {
446
- tools[key] = toolkitEntryToMastraTool(entry, p);
447
- }
448
- return tools;
449
- },
450
- };
451
- }
452
- /**
453
- * Wrap a single {@link AppKitToolkitEntry} as a Mastra tool whose
454
- * `execute` dispatches back through `plugin.executeAgentTool(...)` so
455
- * AppKit's OBO auth (`asUser`) and telemetry spans stay intact. JSON
456
- * Schema parameters pass through unchanged - Mastra's `PublicSchema`
457
- * accepts `JSONSchema7` directly via `@mastra/schema-compat`.
458
- */
459
- function toolkitEntryToMastraTool(entry, plugin) {
460
- return createTool({
461
- id: `${entry.pluginName}__${entry.localName}`,
462
- description: entry.def.description,
463
- ...(entry.def.parameters ? { inputSchema: entry.def.parameters } : {}),
464
- execute: async (input, context) => {
465
- const signal = context
466
- ?.abortSignal;
467
- return plugin.executeAgentTool(entry.localName, input, signal);
468
- },
469
- });
470
- }
@@ -1,153 +0,0 @@
1
- /**
2
- * Chart planner + chart cache.
3
- *
4
- * Self-contained chart subsystem with two layers:
5
- *
6
- * 1. Inner planner agent (private). Pure dataset-in /
7
- * `EChartsOption`-out brain. Driven by {@link prepareChart};
8
- * callers never instantiate it directly.
9
- * 2. {@link prepareChart}: orchestration on top of the planner.
10
- * Mints a `chartId`, caches an empty `{ chartId }` record
11
- * synchronously, then resolves the dataset and runs the
12
- * planner in the background. The terminal entry settles with
13
- * either `result` (success) or `error` (failure). Both
14
- * undefined means the entry is still processing.
15
- *
16
- * The cache surface ({@link fetchChart}) is the only state the
17
- * HTTP route and the chart-producing tools share. `prepareChart`
18
- * is dataset-agnostic - callers supply a `resolveData` callback
19
- * that fetches the rows however they like (Genie statement, inline
20
- * dataset, custom API). The module has no knowledge of Genie or
21
- * statement ids; those concerns live in the tools that wrap it.
22
- *
23
- * Wire-format schemas live in `@dbx-tools/appkit-mastra-shared` so
24
- * the demo client and any other UI consumer share the exact same
25
- * shape this module reads and writes.
26
- */
27
- import { type Chart } from "@dbx-tools/appkit-mastra-shared";
28
- import type { RequestContext } from "@mastra/core/request-context";
29
- import { z } from "zod";
30
- import type { MastraPluginConfig } from "./config.js";
31
- /**
32
- * Canonical planner input shape. Tools that source rows from an
33
- * inline dataset (`render_data`) use it as their `inputSchema`
34
- * verbatim; tools that resolve rows from a remote (`prepare_chart`
35
- * over a Genie statement) `omit({ data })` and `extend` with their
36
- * own identifier field, so the field-level `.describe()` text
37
- * stays a single source of truth. Server-only - the UI never
38
- * sees a planner request, only the resolved {@link Chart}.
39
- */
40
- export declare const chartPlannerRequestSchema: z.ZodObject<{
41
- title: z.ZodString;
42
- description: z.ZodOptional<z.ZodString>;
43
- data: z.ZodReadonly<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
44
- }, z.core.$strip>;
45
- export type ChartPlannerRequest = z.infer<typeof chartPlannerRequestSchema>;
46
- /** Inputs to {@link prepareChart}. */
47
- export interface PrepareChartOptions {
48
- /** Plugin config; resolves the planner agent's model. */
49
- config: MastraPluginConfig;
50
- /** Display title forwarded to the planner agent. */
51
- title?: string;
52
- /** Optional intent hint forwarded to the planner agent. */
53
- description?: string;
54
- /**
55
- * Resolves the rows to chart. Called once, in the background.
56
- * Any thrown error lands in the cache as the entry's `error`
57
- * field (never propagated to the caller of {@link prepareChart}).
58
- * An empty `rows` array is rejected as `"dataset has no rows;
59
- * nothing to chart"`.
60
- */
61
- resolveData: (signal?: AbortSignal) => Promise<{
62
- rows: ReadonlyArray<Record<string, unknown>>;
63
- }>;
64
- /**
65
- * Per-request `RequestContext`. Forwarded to the planner agent so
66
- * user-scoped model resolution (OBO) stays in effect.
67
- */
68
- requestContext?: RequestContext;
69
- /**
70
- * Cooperative cancellation. Forwarded to `resolveData` and the
71
- * planner agent. Note: the chart task continues running in the
72
- * background after the parent request ends, so external abort
73
- * signals are best-effort; typical use is to leave this unset
74
- * and let the 1h TTL cap stale entries.
75
- */
76
- signal?: AbortSignal;
77
- }
78
- /**
79
- * Mint a `chartId`, cache an empty `{ chartId }` placeholder
80
- * synchronously, and kick off a background task that resolves the
81
- * dataset and runs the planner. Returns the `chartId` once the
82
- * placeholder lands so the first {@link fetchChart} call always
83
- * sees an entry (no spurious 404 race).
84
- *
85
- * The background task swallows its own failures and writes them
86
- * as `error` entries, so callers never see a rejected promise.
87
- * Cache state machine:
88
- *
89
- * - just after this call returns: `{ chartId }` (processing)
90
- * - on planner success: `{ chartId, result }`
91
- * - on data / planner failure: `{ chartId, error }`
92
- */
93
- export declare function prepareChart(opts: PrepareChartOptions): Promise<{
94
- chartId: string;
95
- }>;
96
- /** Inputs to {@link fetchChart}. */
97
- export interface FetchChartOptions {
98
- /**
99
- * Server-side polling budget in ms. When the entry stays in
100
- * the processing state past this window, the helper returns the
101
- * last seen value (still processing) so the client can re-poll.
102
- * Defaults to {@link DEFAULT_FETCH_TIMEOUT_MS} (60s).
103
- */
104
- timeoutMs?: number;
105
- /**
106
- * Poll interval in ms. Defaults to
107
- * {@link DEFAULT_FETCH_INTERVAL_MS} (250ms).
108
- */
109
- intervalMs?: number;
110
- /** External cancellation handle (e.g. request `req.signal`). */
111
- signal?: AbortSignal;
112
- }
113
- /**
114
- * Long-poll the chart cache until the entry settles (`result` or
115
- * `error` set), the entry is missing, or the server-side timeout
116
- * elapses.
117
- *
118
- * Returns:
119
- * - the resolved {@link Chart} when it settled, errored, or
120
- * stayed in processing past `timeoutMs` (so the client can
121
- * re-poll);
122
- * - `undefined` when the entry is missing or expired (the
123
- * consumer should treat as 404).
124
- *
125
- * `signal` lets the caller cancel ahead of timeout (e.g. the HTTP
126
- * request closed). Cancellation propagates to the inter-poll sleep
127
- * so the helper returns immediately.
128
- */
129
- export declare function fetchChart(chartId: string, options?: FetchChartOptions): Promise<Chart | undefined>;
130
- /**
131
- * Build the `render_data` Mastra tool bound to the given plugin
132
- * config. Auto-wired as a system tool on every agent (see
133
- * `agents.ts`); per-agent tools can shadow it by registering a
134
- * same-named entry.
135
- *
136
- * Thin wrapper over {@link prepareChart} for callers that already
137
- * have a dataset in hand. Mints a `chartId` synchronously, caches
138
- * an empty placeholder, and kicks off the chart-planner in the
139
- * background. Returns just the `chartId`; the host UI resolves
140
- * `[chart:<chartId>]` markers by hitting the plugin's
141
- * `/embed/chart/:id` route.
142
- *
143
- * For Genie statement results, prefer the Genie agent's
144
- * `prepare_chart` tool, which accepts a `statement_id` and
145
- * resolves the rows lazily.
146
- */
147
- export declare function buildRenderDataTool(config: MastraPluginConfig): import("@mastra/core/tools").Tool<{
148
- title: string;
149
- data: readonly Record<string, unknown>[];
150
- description?: string | undefined;
151
- }, {
152
- chartId: string;
153
- }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "render_data", unknown>;