@dbx-tools/appkit-mastra 0.1.5 → 0.1.13

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 (42) hide show
  1. package/README.md +735 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +1 -0
  4. package/dist/src/agents.js +18 -8
  5. package/dist/src/chart.d.ts +101 -35
  6. package/dist/src/chart.js +178 -62
  7. package/dist/src/config.d.ts +13 -0
  8. package/dist/src/genie.d.ts +23 -8
  9. package/dist/src/genie.js +137 -101
  10. package/dist/src/history.js +14 -0
  11. package/dist/src/memory.d.ts +21 -0
  12. package/dist/src/memory.js +47 -2
  13. package/dist/src/model.js +18 -14
  14. package/dist/src/observability.d.ts +33 -0
  15. package/dist/src/observability.js +71 -0
  16. package/dist/src/plugin.d.ts +1 -1
  17. package/dist/src/plugin.js +32 -4
  18. package/dist/src/processors/strip-stale-charts.d.ts +29 -0
  19. package/dist/src/processors/strip-stale-charts.js +96 -0
  20. package/dist/src/server.js +10 -0
  21. package/dist/src/serving.js +19 -2
  22. package/dist/src/tools/email.d.ts +74 -0
  23. package/dist/src/tools/email.js +122 -0
  24. package/dist/tsconfig.build.tsbuildinfo +1 -0
  25. package/index.ts +1 -0
  26. package/package.json +23 -25
  27. package/src/agents.ts +19 -6
  28. package/src/chart.ts +232 -64
  29. package/src/config.ts +13 -0
  30. package/src/genie.ts +179 -116
  31. package/src/history.ts +19 -7
  32. package/src/memory.ts +55 -2
  33. package/src/model.ts +18 -13
  34. package/src/observability.ts +92 -0
  35. package/src/plugin.ts +33 -4
  36. package/src/processors/strip-stale-charts.ts +105 -0
  37. package/src/server.ts +11 -0
  38. package/src/serving.ts +21 -2
  39. package/src/tools/email.ts +147 -0
  40. package/dist/src/render-chart-route.d.ts +0 -33
  41. package/dist/src/render-chart-route.js +0 -120
  42. package/src/render-chart-route.ts +0 -141
@@ -1,141 +0,0 @@
1
- /**
2
- * Chart-render HTTP endpoint for the Mastra plugin.
3
- *
4
- * The `render_data` tool returns immediately with a `chartId` and
5
- * emits the dataset over `ctx.writer`; the client then POSTs that
6
- * dataset to this endpoint to actually run the chart-planner
7
- * agent and get back an Echarts `EChartsOption` JSON. Planning
8
- * happens out-of-band so the calling agent's response stream
9
- * doesn't sit idle waiting for it - the model can finish the
10
- * report while the client is still rendering charts.
11
- *
12
- * Auth flows through the standard Mastra middleware: the route
13
- * sits in the same dispatcher pipeline as `chatRoute` /
14
- * `historyRoute`, so by the time the handler runs the
15
- * `RequestContext` is populated with the workspace user and
16
- * the chart-planner's model resolver has the OBO token it
17
- * needs.
18
- */
19
-
20
- import type {
21
- RenderChartRequest,
22
- RenderChartResponse,
23
- } from "@dbx-tools/appkit-mastra-shared";
24
- import { registerApiRoute } from "@mastra/core/server";
25
-
26
- import { runChartPlanner } from "./chart.js";
27
- import type { MastraPluginConfig } from "./config.js";
28
-
29
- /** Hard cap so a misbehaving client can't hand us a million-row payload. */
30
- const MAX_ROWS = 5_000;
31
- /**
32
- * Hard cap on the JSON body the route accepts (in bytes). Mirrors
33
- * the same intent as {@link MAX_ROWS}: bound the chart-planner's
34
- * prompt size and protect against accidental denial-of-service
35
- * from a runaway tool that ships an enormous payload.
36
- */
37
- const MAX_BODY_BYTES = 2 * 1024 * 1024;
38
-
39
- /** Options accepted by {@link renderChartRoute}. */
40
- export interface RenderChartRouteOptions {
41
- path: string;
42
- config: MastraPluginConfig;
43
- }
44
-
45
- /**
46
- * Register a `POST <path>` Mastra custom API route that runs the
47
- * chart-planner agent against a dataset and returns an Echarts
48
- * `EChartsOption` JSON.
49
- *
50
- * Body shape: {@link RenderChartRequest}; response:
51
- * {@link RenderChartResponse}.
52
- */
53
- export function renderChartRoute(options: RenderChartRouteOptions) {
54
- const { path, config } = options;
55
- return registerApiRoute(path, {
56
- method: "POST",
57
- handler: async (c) => {
58
- const requestContext = c.get("requestContext");
59
-
60
- // Hono parses the body as JSON; we still validate shape /
61
- // size since the tool's structured output is a contract,
62
- // not a guarantee, and the route is publicly mountable.
63
- const raw = (await c.req.json().catch(() => null)) as unknown;
64
- const validation = validateBody(raw);
65
- if ("error" in validation) {
66
- return c.json({ error: validation.error }, 400);
67
- }
68
- const { title, description, data } = validation.body;
69
-
70
- try {
71
- const result = await runChartPlanner({
72
- config,
73
- ...(requestContext ? { requestContext } : {}),
74
- title,
75
- ...(description ? { description } : {}),
76
- data,
77
- });
78
- const payload: RenderChartResponse = {
79
- option: result.option,
80
- chartType: result.chartType,
81
- };
82
- return c.json(payload);
83
- } catch (err) {
84
- const message = err instanceof Error ? err.message : String(err);
85
- return c.json({ error: message }, 500);
86
- }
87
- },
88
- });
89
- }
90
-
91
- type ValidationResult =
92
- | { body: RenderChartRequest }
93
- | { error: string };
94
-
95
- /**
96
- * Best-effort body validation. Surfaces a 400 for malformed input
97
- * instead of letting a downstream `.map` / `.length` blow up
98
- * inside the planner agent. Field-level shape mirrors
99
- * {@link RenderChartRequest}.
100
- */
101
- function validateBody(raw: unknown): ValidationResult {
102
- if (!raw || typeof raw !== "object") {
103
- return { error: "request body must be a JSON object" };
104
- }
105
- const r = raw as Record<string, unknown>;
106
- const title = r.title;
107
- if (typeof title !== "string" || title.length === 0) {
108
- return { error: "`title` must be a non-empty string" };
109
- }
110
- if (r.description !== undefined && typeof r.description !== "string") {
111
- return { error: "`description` must be a string when provided" };
112
- }
113
- if (!Array.isArray(r.data)) {
114
- return { error: "`data` must be an array of row objects" };
115
- }
116
- if (r.data.length === 0) {
117
- return { error: "`data` must contain at least one row" };
118
- }
119
- if (r.data.length > MAX_ROWS) {
120
- return { error: `\`data\` exceeds the per-request limit of ${MAX_ROWS} rows` };
121
- }
122
- for (const [i, row] of r.data.entries()) {
123
- if (!row || typeof row !== "object" || Array.isArray(row)) {
124
- return { error: `data[${i}] must be a plain object` };
125
- }
126
- }
127
- // Approximate body-size check; spares us pulling Buffer in.
128
- const approximateBytes = JSON.stringify(r.data).length;
129
- if (approximateBytes > MAX_BODY_BYTES) {
130
- return {
131
- error: `\`data\` exceeds the per-request size limit of ${MAX_BODY_BYTES} bytes`,
132
- };
133
- }
134
- return {
135
- body: {
136
- title,
137
- ...(typeof r.description === "string" ? { description: r.description } : {}),
138
- data: r.data as Array<Record<string, unknown>>,
139
- },
140
- };
141
- }