@dbx-tools/appkit-mastra 0.1.25 → 0.1.27

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.
@@ -191,7 +191,7 @@ export interface MastraPluginConfig extends BasePluginConfig {
191
191
  * processor that strips `chartId` fields from prior assistant
192
192
  * tool-invocation results before they reach the model. This
193
193
  * prevents the model from reusing turn-scoped chartIds it sees
194
- * in memory recall (which would leave `[[chart:<id>]]` markers
194
+ * in memory recall (which would leave `[chart:<id>]` markers
195
195
  * pointing at writer events that no longer exist).
196
196
  *
197
197
  * Set to `false` to opt out - useful if a non-default agent
@@ -266,22 +266,25 @@ export interface MastraPluginConfig extends BasePluginConfig {
266
266
  */
267
267
  genieSpaceCacheTtlMs?: number;
268
268
  /**
269
- * Maximum LLM steps the Genie agent gets per turn.
270
- * Each step is one round-trip to the underlying model
271
- * (`get_space_description`, each `ask_genie` call, and the
272
- * mandatory `submit_summary` closer all consume one step).
269
+ * Maximum LLM steps each agent gets per turn. One step = one
270
+ * round-trip to the underlying model (a tool call consumes a
271
+ * step, the final-text reply consumes one too). Applies to
272
+ * every agent registered through {@link MastraPluginConfig.agents}
273
+ * - per-agent overrides aren't surfaced yet because the same
274
+ * ceiling has been sufficient across every workload we've run.
273
275
  *
274
- * Defaults to 16, which fits ~10 `ask_genie` calls plus
275
- * grounding plus the summary closer - matches the
276
- * decomposition pattern the Genie agent instructions prescribe
277
- * ("2-6 ask_genie calls for any non-trivial question").
278
- * Mastra's own `agent.generate` default of 5 would cut the
279
- * Genie agent off after 2-3 Genie calls, so explicitly raising
280
- * the ceiling here is what lets the agent-mode loop play out.
276
+ * Defaults to {@link DEFAULT_AGENT_MAX_STEPS} (25), sized to fit
277
+ * a decomposed Genie turn (grounding + several `ask_genie` calls
278
+ * + `prepare_chart` per dataset + the final-text reply) with
279
+ * headroom for the model to chain a couple of follow-ups before
280
+ * answering. Mastra's own `agent.generate` default of 5 would
281
+ * cut multi-step orchestration off after 2-3 tool calls, so
282
+ * explicitly raising the ceiling here is what lets the
283
+ * agent-mode loop play out.
281
284
  *
282
- * Lower this when an unusually slow or expensive model makes
283
- * long turns unaffordable; raise it for exploratory workloads
284
- * that need to drill into a dataset.
285
+ * Lower when an unusually slow or expensive model makes long
286
+ * turns unaffordable; raise for exploratory workloads that need
287
+ * to drill deep into a dataset within a single turn.
285
288
  */
286
- genieAgentMaxSteps?: number;
289
+ agentMaxSteps?: number;
287
290
  }
@@ -1,46 +1,61 @@
1
1
  /**
2
- * Genie agent for Mastra.
2
+ * Genie tools for Mastra.
3
3
  *
4
- * Each configured Genie space exposes a single Mastra tool to the
5
- * calling agent (`genie` for the `"default"` alias, `genie_<alias>`
6
- * otherwise). When invoked, the tool runs end-to-end:
4
+ * Each configured Genie space is surfaced as a small set of flat
5
+ * Mastra tools the calling agent can drive directly - no inner
6
+ * orchestrator agent. The central agent decomposes user questions,
7
+ * picks which Genie space to ask, and composes the final reply.
7
8
  *
8
- * 1. Pulls the per-request {@link WorkspaceClient} off
9
- * `ctx.requestContext` (stamped by `MastraServer`) and emits a
10
- * `started` writer event so the host UI can show progress
11
- * immediately, before any LLM round-trip.
12
- * 2. Spins up a per-call inner Mastra `Agent` with three tools:
13
- * - `ask_genie`: drives one `genieEventChat` turn, fetches
14
- * the matching statement's rows when the turn ran SQL,
15
- * and forwards every wire event (status, thinking, sql,
16
- * rows) through `ctx.writer` for streaming UI updates.
17
- * - `get_space_description`: cheap title / description /
18
- * warehouse id lookup for grounding.
19
- * - `get_space_serialized`: full `GenieSpace` JSON for
20
- * column-level grounding when the description isn't
21
- * enough.
22
- * 3. Runs the inner agent with `structuredOutput` (Mastra's
23
- * two-pass mode + `jsonPromptInjection`) to coerce the
24
- * agent's final answer into a tagged
25
- * `[{type:"text"|"data", ...}]` array. The two-pass design
26
- * avoids Databricks Model Serving's `response_format` +
27
- * `tools` collision; prompt injection sidesteps the
28
- * separate `response_format` + streaming collision in the
29
- * structuring agent.
30
- * 4. Charts every `data` item in parallel via
31
- * {@link runChartPlanner}, maps `text` items to the shared
32
- * {@link GenieSummaryItem} `string` variant, and returns the
33
- * hydrated {@link GenieAgentResult}.
9
+ * Per-space tools (suffixed with `_<alias>` for non-default
10
+ * aliases):
34
11
  *
35
- * The inner agent talks to Genie directly via
36
- * `@dbx-tools/genie` (`genieEventChat`) and the workspace
37
- * `statementExecution.getStatement` API. AppKit's stock `genie`
38
- * plugin is honored only for its `spaces` config so existing
39
- * AppKit-style wiring keeps working without change.
12
+ * - `ask_genie`: drives one `genieEventChat` turn and
13
+ * forwards every wire event (status, thinking, sql, rows)
14
+ * through `ctx.writer` for streaming UI updates. Returns
15
+ * the terminal `GenieMessage` only - rows are NOT fetched
16
+ * eagerly.
17
+ * - `get_space_description`: cheap title / description /
18
+ * warehouse id lookup for grounding.
19
+ * - `get_space_serialized`: full `GenieSpace` JSON for
20
+ * column-level grounding when the description isn't enough.
21
+ *
22
+ * Space-agnostic shared tools (registered once, regardless of
23
+ * how many spaces are wired):
24
+ *
25
+ * - `get_statement`: opt-in lookup of a Genie statement's rows
26
+ * by `statement_id` (with a row `limit`). The agent calls
27
+ * this only when it needs to read values to reason about
28
+ * them; if the data is just being displayed, it embeds a
29
+ * `[data:<statement_id>]` marker in prose instead and lets
30
+ * the host UI resolve it.
31
+ * - `prepare_chart`: mints a short `chartId`, kicks off a
32
+ * background task that fetches the statement's rows and
33
+ * runs the chart-planner, and caches the resolved Echarts
34
+ * spec under the id (1h TTL). Returns the `chartId`
35
+ * synchronously so the agent embeds `[chart:<chartId>]`
36
+ * markers in prose without blocking on chart generation;
37
+ * the host UI fetches the cached chart by id once it's
38
+ * ready (see {@link fetchChart}).
39
+ *
40
+ * Each tool's `execute` pulls the per-request
41
+ * {@link WorkspaceClient} off `ctx.requestContext` (stamped by
42
+ * `MastraServer` under {@link MASTRA_USER_KEY}) and the per-call
43
+ * `writer` / `abortSignal` off `ctx`, so the tools are stateless
44
+ * across requests and the central agent owns the loop.
45
+ *
46
+ * The tools talk to Genie directly via `@dbx-tools/genie`
47
+ * (`genieEventChat`); statement-row fetching is delegated to
48
+ * {@link fetchStatementData} from `./statement.js`, which wraps
49
+ * the workspace `statementExecution.getStatement` API. AppKit's
50
+ * stock `genie` plugin is honored only for its `spaces` config
51
+ * so existing AppKit-style wiring keeps working without change.
52
+ *
53
+ * Suggested orchestration prompt for the central agent lives in
54
+ * {@link GENIE_INSTRUCTIONS}; compose it into the agent's own
55
+ * `instructions` when you want the canonical "how to drive the
56
+ * Genie tools" guidance.
40
57
  */
41
- import { type ChartEvent } from "@dbx-tools/appkit-mastra-shared";
42
58
  import { appkitUtils } from "@dbx-tools/shared";
43
- import type { RequestContext } from "@mastra/core/request-context";
44
59
  import type { MastraTools } from "./agents.js";
45
60
  import type { MastraPluginConfig } from "./config.js";
46
61
  /** Default alias used when a single unnamed Genie space is wired up. */
@@ -50,76 +65,40 @@ export interface GenieSpaceConfig {
50
65
  /** Genie `space_id`. Required; resolves via `client.genie.getSpace`. */
51
66
  spaceId: string;
52
67
  /**
53
- * Optional human-readable description appended to the Genie
54
- * tool's description so the calling LLM has hints about
55
- * *what data* this space covers (e.g. "orders, returns,
68
+ * Optional human-readable description appended to the per-space
69
+ * tool descriptions so the calling LLM has hints about *what
70
+ * data* this space covers (e.g. "orders, returns,
56
71
  * fulfillment"). When omitted, only the space's own
57
- * `description` (fetched on first use) is shown.
72
+ * `description` (fetched on first use of `get_space_description`)
73
+ * is shown.
58
74
  */
59
75
  hint?: string;
60
76
  }
61
77
  /** Map of alias -> space config. Accepts either explicit objects or bare space ids. */
62
78
  export type GenieSpacesConfig = Record<string, GenieSpaceConfig | string>;
63
79
  /**
64
- * Get the chart inventory map for this request, creating it on
65
- * first access. Subsequent reads return the same map so callers
66
- * mutate in place. The map is request-scoped (collected with the
67
- * `RequestContext` at end of request), so there's no per-process
68
- * leak.
69
- */
70
- export declare function chartInventoryFromContext(requestContext: RequestContext): Map<string, ChartEvent>;
71
- /**
72
- * Options for {@link createGenieTool}. Only carries config that
73
- * doesn't vary per request - the per-request {@link WorkspaceClient},
74
- * `RequestContext`, writer, and abort signal flow through the
75
- * tool's `execute(_, ctx)` and are not captured here.
76
- */
77
- export interface CreateGenieToolOptions {
78
- /** Genie space id this tool targets. */
79
- spaceId: string;
80
- /** Plugin config; resolves the LLM and chart planner agent. */
81
- config: MastraPluginConfig;
82
- /** Override the registered tool id. Defaults to `"genie"`. */
83
- toolId?: string;
84
- /** Override the tool description shown to the calling LLM. */
85
- toolDescription?: string;
86
- /**
87
- * Override the inner agent's max tool-loop steps. Defaults to
88
- * {@link DEFAULT_MAX_STEPS}.
89
- */
90
- maxSteps?: number;
91
- }
92
- /**
93
- * Build the calling agent's Genie tool. The returned Mastra tool
94
- * runs end-to-end on each invocation:
80
+ * Suggested orchestration prompt for the central agent that owns
81
+ * the Genie tools. Compose into your agent's `instructions` to
82
+ * get the canonical "decompose questions, ask Genie focused
83
+ * sub-questions, place data / chart markers in prose" behavior:
95
84
  *
96
- * 1. Pull the per-request `WorkspaceClient` off
97
- * `ctx.requestContext` (stamped by `MastraServer` under
98
- * {@link MASTRA_USER_KEY}) and emit a `started` writer
99
- * event so the host UI shows progress immediately.
100
- * 2. Spin up the inner Mastra agent + three tools, fresh per
101
- * call so the row cache stays invocation-scoped.
102
- * 3. Run the agent with `structuredOutput` against
103
- * {@link agentSummarySchema}. Mastra's two-pass design keeps
104
- * the inner loop tools-only (no `response_format`), so the
105
- * Databricks Model Serving `response_format`+`tools`
106
- * collision never fires.
107
- * 4. Walk the returned `[text|data][]`, map `text` items to
108
- * shared `GenieSummaryItem.string`, and chart every `data`
109
- * item in parallel via {@link runChartPlanner} to a
110
- * `GenieSummaryItem.visualize`. Items referencing a missing
111
- * `statementId` are dropped with a warn log; chart-planner
112
- * failures leave `dataset.chart` unset so the host UI falls
113
- * back to a table.
114
- */
115
- export declare function createGenieTool(opts: CreateGenieToolOptions): import("@mastra/core/tools").Tool<any, any, any, any, import("@mastra/core/tools").ToolExecutionContext<any, any, unknown>, string, unknown>;
116
- /**
117
- * Default tool id for a wired Genie alias. The well-known
118
- * `default` alias collapses to `genie`; every other alias gets a
119
- * `genie_` prefix so multi-space registrations stay
120
- * disambiguated.
85
+ * ```ts
86
+ * createAgent({
87
+ * instructions: `${myAgentInstructions}\n\n${GENIE_INSTRUCTIONS}`,
88
+ * tools(plugins) {
89
+ * return { ...plugins.genie?.toolkit() };
90
+ * },
91
+ * });
92
+ * ```
93
+ *
94
+ * The prompt references the bare tool names (`ask_genie`,
95
+ * `get_space_description`, `get_space_serialized`,
96
+ * `get_statement`, `prepare_chart`) used for the single-space
97
+ * default alias. Multi-space deployments should write their own
98
+ * variant that names the suffixed per-space tools
99
+ * (e.g. `ask_genie_sales`).
121
100
  */
122
- export declare function defaultGenieToolName(alias: string): string;
101
+ export declare const GENIE_INSTRUCTIONS: string;
123
102
  /**
124
103
  * Normalize the {@link GenieSpacesConfig} record. Bare-string
125
104
  * entries (`{ default: "01ef..." }`) get wrapped as
@@ -154,14 +133,19 @@ export declare function normalizeGenieSpaces(spaces: GenieSpacesConfig | Record<
154
133
  */
155
134
  export declare function resolveGenieSpaces(config: MastraPluginConfig, context: appkitUtils.PluginContextLike | undefined): Record<string, GenieSpaceConfig>;
156
135
  /**
157
- * Build one Mastra tool per configured Genie space. Each tool is
158
- * a thin {@link createGenieTool} wrapper with the alias-derived
159
- * id and a hint-flavored description so the calling LLM knows
160
- * which space covers what data.
136
+ * Build the flat Mastra tools record for every configured Genie
137
+ * space. Two shared, space-agnostic tools (`get_statement`,
138
+ * `prepare_chart`) are registered once regardless of how many
139
+ * spaces are wired; the per-space tools (`ask_genie`,
140
+ * `get_space_description`, `get_space_serialized`) are suffixed
141
+ * with `_<alias>` for non-default aliases so multi-space
142
+ * deployments stay disambiguated.
161
143
  *
162
- * Returns a record keyed by tool id, ready to spread into an
163
- * `Agent`'s `tools` map (or surfaced via
164
- * `plugins.genie?.toolkit()`).
144
+ * Returns a record keyed by tool id, ready to spread into the
145
+ * central `Agent`'s `tools` map (or surfaced via the
146
+ * `plugins.genie?.toolkit()` callback). Returns an empty record
147
+ * when `spaces` resolves to zero entries so the caller can spread
148
+ * safely.
165
149
  */
166
150
  export declare function buildGenieTools(opts: {
167
151
  spaces: GenieSpacesConfig | Record<string, GenieSpaceConfig>;
@@ -170,7 +154,7 @@ export declare function buildGenieTools(opts: {
170
154
  /**
171
155
  * Plugin-toolkit adapter so the `plugins.genie?.toolkit()` lookup
172
156
  * inside an agent's `tools(plugins)` callback returns the
173
- * Genie agent-backed tools instead of throwing on missing plugin.
157
+ * flat Genie tools record instead of throwing on missing plugin.
174
158
  * Mirrors AppKit's `PluginToolkitProvider` shape.
175
159
  */
176
160
  export declare function buildGenieToolkitProvider(opts: {