drizzle-cube 0.4.8 → 0.4.9

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 (28) hide show
  1. package/dist/adapters/express/index.cjs +1 -1
  2. package/dist/adapters/express/index.js +1 -1
  3. package/dist/adapters/fastify/index.cjs +1 -1
  4. package/dist/adapters/fastify/index.js +1 -1
  5. package/dist/adapters/{handler-odjn7MIB.js → handler-CSHsefnC.js} +270 -185
  6. package/dist/adapters/{handler-BLcxTuwi.cjs → handler-Xe_2ItOo.cjs} +13 -13
  7. package/dist/adapters/hono/index.cjs +1 -1
  8. package/dist/adapters/hono/index.js +1 -1
  9. package/dist/adapters/nextjs/index.cjs +1 -1
  10. package/dist/adapters/nextjs/index.js +1 -1
  11. package/dist/client/chunks/{analysis-builder-Bov_gLsf.js → analysis-builder-DFt9p8tj.js} +137 -137
  12. package/dist/client/chunks/{analysis-builder-Bov_gLsf.js.map → analysis-builder-DFt9p8tj.js.map} +1 -1
  13. package/dist/client/chunks/{analysis-builder-shared-NBk6y0md.js → analysis-builder-shared-DOHV2W8A.js} +713 -787
  14. package/dist/client/chunks/analysis-builder-shared-DOHV2W8A.js.map +1 -0
  15. package/dist/client/chunks/{components-O0hh7ooo.js → components-8FAXo62Z.js} +1495 -1416
  16. package/dist/client/chunks/components-8FAXo62Z.js.map +1 -0
  17. package/dist/client/components/AgenticNotebook/NotebookPortletBlock.d.ts +1 -0
  18. package/dist/client/components.js +8 -8
  19. package/dist/client/index.js +655 -584
  20. package/dist/client/index.js.map +1 -1
  21. package/dist/client/stores/notebookStore.d.ts +2 -0
  22. package/dist/client/styles.css +1 -1
  23. package/dist/client-bundle-stats.html +1 -1
  24. package/dist/server/index.cjs +13 -13
  25. package/dist/server/index.js +1775 -1690
  26. package/package.json +1 -1
  27. package/dist/client/chunks/analysis-builder-shared-NBk6y0md.js.map +0 -1
  28. package/dist/client/chunks/components-O0hh7ooo.js.map +0 -1
@@ -1,40 +1,40 @@
1
- import { h as E, Q as q, j as z, D as N } from "./mcp-transport-CU5g9bxj.js";
2
- import { handleDiscover as Y, handleLoad as L } from "./utils.js";
3
- function M(s) {
4
- if (s.length === 0)
1
+ import { h as q, Q as N, j as P, D as Y } from "./mcp-transport-CU5g9bxj.js";
2
+ import { handleDiscover as z, handleLoad as M } from "./utils.js";
3
+ function R(r) {
4
+ if (r.length === 0)
5
5
  return "No cubes are currently available.";
6
6
  const t = ["## Available Cubes", ""];
7
- for (const a of s) {
8
- if (t.push(`### ${a.name}`), a.description && t.push(a.description), a.measures && a.measures.length > 0) {
7
+ for (const i of r) {
8
+ if (t.push(`### ${i.name}`), i.description && t.push(i.description), i.measures && i.measures.length > 0) {
9
9
  t.push(""), t.push("**Measures:**");
10
- for (const i of a.measures) {
11
- const e = i.description ? ` - ${i.description}` : "";
12
- t.push(`- \`${a.name}.${i.name}\` (${i.type})${e}`);
10
+ for (const a of i.measures) {
11
+ const e = a.description ? ` - ${a.description}` : "";
12
+ t.push(`- \`${i.name}.${a.name}\` (${a.type})${e}`);
13
13
  }
14
14
  }
15
- if (a.dimensions && a.dimensions.length > 0) {
15
+ if (i.dimensions && i.dimensions.length > 0) {
16
16
  t.push(""), t.push("**Dimensions:**");
17
- for (const i of a.dimensions) {
18
- const e = i.description ? ` - ${i.description}` : "";
19
- t.push(`- \`${a.name}.${i.name}\` (${i.type})${e}`);
17
+ for (const a of i.dimensions) {
18
+ const e = a.description ? ` - ${a.description}` : "";
19
+ t.push(`- \`${i.name}.${a.name}\` (${a.type})${e}`);
20
20
  }
21
21
  }
22
- if (a.relationships && a.relationships.length > 0) {
22
+ if (i.relationships && i.relationships.length > 0) {
23
23
  t.push(""), t.push("**Joins:**");
24
- for (const i of a.relationships)
25
- t.push(`- → \`${i.targetCube}\` (${i.relationship})`);
24
+ for (const a of i.relationships)
25
+ t.push(`- → \`${a.targetCube}\` (${a.relationship})`);
26
26
  }
27
- a.meta?.eventStream && (t.push(""), t.push("**Event Stream:** Yes (supports funnel, flow, retention queries)"), a.meta.eventStream.bindingKey && t.push(`- Binding key: \`${a.name}.${a.meta.eventStream.bindingKey}\``), a.meta.eventStream.timeDimension && t.push(`- Time dimension: \`${a.name}.${a.meta.eventStream.timeDimension}\``)), t.push("");
27
+ i.meta?.eventStream && (t.push(""), t.push("**Event Stream:** Yes (supports funnel, flow, retention queries)"), i.meta.eventStream.bindingKey && t.push(`- Binding key: \`${i.name}.${i.meta.eventStream.bindingKey}\``), i.meta.eventStream.timeDimension && t.push(`- Time dimension: \`${i.name}.${i.meta.eventStream.timeDimension}\``)), t.push("");
28
28
  }
29
29
  return t.join(`
30
30
  `);
31
31
  }
32
- function S(s) {
33
- return s.messages.map((t) => t.content.text).join(`
32
+ function F(r) {
33
+ return r.messages.map((t) => t.content.text).join(`
34
34
 
35
35
  `);
36
36
  }
37
- function R(s) {
37
+ function L(r) {
38
38
  return [
39
39
  "# Drizzle Cube Analytics Agent",
40
40
  "",
@@ -78,15 +78,14 @@ function R(s) {
78
78
  "- Before calling `add_portlet`, verify the query is valid: all fields in `order` must also appear in `measures` or `dimensions`",
79
79
  '- Never put data tables in markdown blocks — use `add_portlet` with chartType "table" instead',
80
80
  "- Think out loud in the notebook: use `add_markdown` to share your reasoning at each step so users can follow along",
81
+ "- NEVER use emojis in text responses or markdown content — no 📊, 📈, ✅, 🔍, etc. Write in plain, professional language.",
81
82
  "",
82
83
  "## Chart Selection Guide",
83
84
  "",
84
- "Choose chart types based on the user's intent and data shape:",
85
+ "Choose the chart type that best communicates the answer to the user's question. Think about what the data represents and what insight the user needs — do NOT default to the first option in this table. Consider the number of data points, whether values are categorical or temporal, and whether the user is comparing, trending, or summarizing.",
85
86
  "",
86
87
  "| Intent / Data Shape | Chart Type |",
87
88
  "|---|---|",
88
- "| Single headline metric (total revenue, user count) | `kpiNumber` |",
89
- "| Headline metric with period-over-period change | `kpiDelta` |",
90
89
  "| Compare discrete categories or rankings | `bar` |",
91
90
  "| Trend over time (one or few series) | `line` |",
92
91
  "| Trend over time showing volume/magnitude | `area` |",
@@ -97,6 +96,8 @@ function R(s) {
97
96
  "| Multi-variable comparison across categories | `radar` |",
98
97
  "| Distribution/spread of values | `boxPlot` |",
99
98
  "| Detailed row-level data or many columns | `table` |",
99
+ "| Single headline number — ONLY when user explicitly asks for a KPI card or single number | `kpiNumber` |",
100
+ "| Headline metric with period-over-period change — ONLY when user asks about change in a single metric | `kpiDelta` |",
100
101
  "",
101
102
  "Analysis-mode-specific chart types (require the corresponding analysis mode):",
102
103
  "",
@@ -108,50 +109,53 @@ function R(s) {
108
109
  "| Retention | `retentionHeatmap` | Cohort × period retention matrix |",
109
110
  "| Retention | `retentionCombined` | Retention with line chart, heatmap, or combined modes |",
110
111
  "",
111
- "Defaults: If unsure, use `bar` for categories, `line` for time series, `table` for exploratory data.",
112
+ '**Chart selection priorities:** Default to `bar` for categories, `line` for time series, `table` for exploratory data. Use `kpiNumber`/`kpiDelta` only as a last resort — they are appropriate only when the user explicitly asks for a single headline number or KPI card. If the query returns multiple rows or the user asks a general question like "show me revenue", prefer `bar` or `table` over `kpiNumber`.',
112
113
  "",
113
114
  "## Analysis Mode Decision Tree",
114
115
  "",
115
116
  "The default mode is **query** (standard measures/dimensions). Switch to a special mode only when the user's question matches:",
116
117
  "",
117
- '- **Funnel mode** — "What is the conversion rate from step A → B → C?" or "How many users complete signup?"',
118
+ '- **Funnel mode** — "What is the conversion rate from step A → B → C?"',
118
119
  " - Requires: an event-stream cube with `capabilities.funnel = true` from `discover_cubes`",
119
- ' - Query format: `{ queryType: "funnel", bindingKey, timeDimension, steps: [...] }`',
120
- " - Chart type: `funnel`",
120
+ " - Execute: `execute_query` with `funnel` param:",
121
+ ' `{ bindingKey: "Events.userId", timeDimension: "Events.timestamp", steps: [{ name: "Signup", filter: { member: "Events.eventName", operator: "equals", values: ["signup"] }}, { name: "Purchase", filter: { member: "Events.eventName", operator: "equals", values: ["purchase"] }}] }`',
122
+ ' - Visualize: `add_portlet` with `chartType: "funnel"` and `query` as JSON string containing `{ "funnel": { ... } }`',
121
123
  "",
122
- '- **Flow mode** — "What paths do users take after signup?" or "Show me the most common navigation flows"',
124
+ '- **Flow mode** — "What paths do users take after signup?"',
123
125
  " - Requires: `capabilities.flow = true` from `discover_cubes`",
124
- ' - Query format: `{ queryType: "flow", bindingKey, timeDimension, startStep, maxSteps }`',
125
- " - Chart types: `sankey` (flow diagram) or `sunburst` (radial paths)",
126
+ " - Execute: `execute_query` with `flow` param:",
127
+ ' `{ bindingKey: "Events.userId", timeDimension: "Events.timestamp", eventDimension: "Events.eventName", startingStep: { name: "Signup", filter: { member: "Events.eventName", operator: "equals", values: ["signup"] }}, stepsBefore: 0, stepsAfter: 3 }`',
128
+ ' - Visualize: `add_portlet` with `chartType: "sankey"` (or `"sunburst"`) and `query` as JSON string containing `{ "flow": { ... } }`',
126
129
  "",
127
- '- **Retention mode** — "What % of users come back after 7 days?" or "Show me weekly retention cohorts"',
130
+ '- **Retention mode** — "What % of users come back after 7 days?"',
128
131
  " - Requires: `capabilities.retention = true` from `discover_cubes`",
129
- ' - Query format: `{ queryType: "retention", bindingKey, timeDimension, retentionStep, ... }`',
130
- " - Chart types: `retentionHeatmap` (cohort matrix) or `retentionCombined` (line + heatmap)",
132
+ " - Execute: `execute_query` with `retention` param:",
133
+ ' `{ timeDimension: "Events.timestamp", bindingKey: "Events.userId", dateRange: { start: "2024-01-01", end: "2024-03-31" }, granularity: "week", periods: 8, retentionType: "classic" }`',
134
+ ' - Visualize: `add_portlet` with `chartType: "retentionCombined"` (or `"retentionHeatmap"`) and `query` as JSON string containing `{ "retention": { ... } }`',
131
135
  "",
132
- "Before using funnel/flow/retention, check the `capabilities` object returned by `discover_cubes`. If the required capability is `false`, explain to the user that the data model does not support that analysis mode and suggest a standard query alternative.",
136
+ "Before using funnel/flow/retention, check the `capabilities` object returned by `discover_cubes`. If the required capability is `false`, explain to the user that the data model does not support that analysis mode.",
133
137
  "",
134
138
  "Event-stream cubes are marked in the Available Cubes section below with **Event Stream: Yes** and list their binding key and time dimension.",
135
139
  "",
136
140
  "---",
137
141
  "",
138
- S(E),
142
+ F(q),
139
143
  "",
140
144
  "---",
141
145
  "",
142
- S(q),
146
+ F(N),
143
147
  "",
144
148
  "---",
145
149
  "",
146
- S(z),
150
+ F(P),
147
151
  "",
148
152
  "---",
149
153
  "",
150
- S(N),
154
+ F(Y),
151
155
  "",
152
156
  "---",
153
157
  "",
154
- M(s)
158
+ R(r)
155
159
  ].join(`
156
160
  `);
157
161
  }
@@ -410,7 +414,7 @@ const H = {
410
414
  description: "Number formatting for values"
411
415
  }
412
416
  ]
413
- }, G = {
417
+ }, K = {
414
418
  label: "Scatter Plot",
415
419
  description: "Reveal correlations between variables",
416
420
  useCase: "Best for identifying patterns, correlations, outliers, and relationships between two measures",
@@ -458,7 +462,7 @@ const H = {
458
462
  description: "Number formatting for Y-axis"
459
463
  }
460
464
  ]
461
- }, Z = {
465
+ }, G = {
462
466
  label: "Bubble Chart",
463
467
  description: "Compare three dimensions of data",
464
468
  useCase: "Best for showing relationships between three variables (X, Y, and size), market analysis",
@@ -524,7 +528,7 @@ const H = {
524
528
  description: "Number formatting for Y-axis and values"
525
529
  }
526
530
  ]
527
- }, X = {
531
+ }, Z = {
528
532
  label: "Radar Chart",
529
533
  description: "Compare multiple metrics across categories",
530
534
  useCase: "Best for multivariate comparisons, performance metrics, strengths/weaknesses analysis",
@@ -563,7 +567,7 @@ const H = {
563
567
  description: "Number formatting for values"
564
568
  }
565
569
  ]
566
- }, U = {
570
+ }, X = {
567
571
  label: "Radial Bar Chart",
568
572
  description: "Circular progress and KPI visualization",
569
573
  useCase: "Best for showing progress toward goals, KPIs, or comparing percentages in a compact form",
@@ -595,7 +599,7 @@ const H = {
595
599
  description: "Number formatting for values"
596
600
  }
597
601
  ]
598
- }, K = {
602
+ }, U = {
599
603
  label: "TreeMap",
600
604
  description: "Visualize hierarchical data with nested rectangles",
601
605
  useCase: "Best for showing part-to-whole relationships in hierarchical data, disk usage, budget allocation",
@@ -637,7 +641,7 @@ const H = {
637
641
  }
638
642
  ],
639
643
  clickableElements: { cell: !0 }
640
- }, Q = {
644
+ }, W = {
641
645
  label: "Data Table",
642
646
  description: "Display detailed tabular data",
643
647
  useCase: "Best for precise values, detailed analysis, sortable/filterable data exploration",
@@ -660,7 +664,7 @@ const H = {
660
664
  description: "Number formatting for numeric values"
661
665
  }
662
666
  ]
663
- }, W = {
667
+ }, Q = {
664
668
  label: "Activity Grid",
665
669
  description: "GitHub-style activity grid showing temporal patterns across different time scales",
666
670
  useCase: "Best for visualizing activity patterns over time. Supports hour (3hr blocks × days), day (days × weeks), week (weeks × months), month (months × quarters), and quarter (quarters × years) granularities",
@@ -694,12 +698,12 @@ const H = {
694
698
  description: "Automatically size blocks to fill portlet width and height while maintaining aspect ratio"
695
699
  }
696
700
  ],
697
- validate: (s) => {
698
- const { dateField: t, valueField: a } = s;
701
+ validate: (r) => {
702
+ const { dateField: t, valueField: i } = r;
699
703
  return !t || Array.isArray(t) && t.length === 0 ? {
700
704
  isValid: !1,
701
705
  message: "Time dimension is required for activity grid"
702
- } : !a || Array.isArray(a) && a.length === 0 ? {
706
+ } : !i || Array.isArray(i) && i.length === 0 ? {
703
707
  isValid: !1,
704
708
  message: "Activity measure is required for intensity mapping"
705
709
  } : { isValid: !0 };
@@ -863,7 +867,7 @@ const H = {
863
867
  }
864
868
  ],
865
869
  displayOptions: ["hideHeader"],
866
- validate: (s) => !s.yAxis || Array.isArray(s.yAxis) && s.yAxis.length === 0 ? {
870
+ validate: (r) => !r.yAxis || Array.isArray(r.yAxis) && r.yAxis.length === 0 ? {
867
871
  isValid: !1,
868
872
  message: "A measure is required for KPI Delta charts"
869
873
  } : { isValid: !0 }
@@ -909,7 +913,7 @@ const H = {
909
913
  }
910
914
  ],
911
915
  displayOptions: ["hideHeader"]
912
- }, ae = {
916
+ }, ie = {
913
917
  label: "Markdown",
914
918
  description: "Display custom markdown content with formatting",
915
919
  useCase: "Perfect for adding documentation, notes, section headers, instructions, or formatted text to dashboards",
@@ -1001,7 +1005,7 @@ Use --- for horizontal rules.`,
1001
1005
  description: "Add an accent-colored border on one side of the content"
1002
1006
  }
1003
1007
  ]
1004
- }, ie = {
1008
+ }, ae = {
1005
1009
  label: "Funnel Chart",
1006
1010
  description: "Show conversion through sequential steps",
1007
1011
  useCase: "Best for visualizing user journey funnels, sales pipelines, or multi-step processes",
@@ -1088,7 +1092,7 @@ Use --- for horizontal rules.`,
1088
1092
  description: "Display 90th percentile time to convert"
1089
1093
  }
1090
1094
  ]
1091
- }, oe = {
1095
+ }, se = {
1092
1096
  label: "Sankey Chart",
1093
1097
  description: "Show flow between states or steps",
1094
1098
  useCase: "Best for visualizing user journey flows, path analysis, or state transitions",
@@ -1144,7 +1148,7 @@ Use --- for horizontal rules.`,
1144
1148
  description: "Hide the statistics footer below the chart"
1145
1149
  }
1146
1150
  ]
1147
- }, se = {
1151
+ }, oe = {
1148
1152
  label: "Sunburst Chart",
1149
1153
  description: "Show hierarchical flow as radial rings",
1150
1154
  useCase: "Best for visualizing forward paths from a starting event in a compact radial layout",
@@ -1260,7 +1264,7 @@ Use --- for horizontal rules.`,
1260
1264
  description: "Number formatting for cell values and legend"
1261
1265
  }
1262
1266
  ],
1263
- validate: (s) => s.xAxis?.length ? s.yAxis?.length ? s.valueField?.length ? { isValid: !0 } : { isValid: !1, message: "Value measure required" } : { isValid: !1, message: "Y-axis dimension required" } : { isValid: !1, message: "X-axis dimension required" }
1267
+ validate: (r) => r.xAxis?.length ? r.yAxis?.length ? r.valueField?.length ? { isValid: !0 } : { isValid: !1, message: "Value measure required" } : { isValid: !1, message: "Y-axis dimension required" } : { isValid: !1, message: "X-axis dimension required" }
1264
1268
  }, ne = {
1265
1269
  label: "Retention Matrix",
1266
1270
  // RetentionHeatmap auto-configures from the retention data structure
@@ -1413,98 +1417,98 @@ Use --- for horizontal rules.`,
1413
1417
  line: $,
1414
1418
  area: B,
1415
1419
  pie: j,
1416
- scatter: G,
1417
- bubble: Z,
1418
- radar: X,
1419
- radialBar: U,
1420
- treemap: K,
1421
- table: Q,
1422
- activityGrid: W,
1420
+ scatter: K,
1421
+ bubble: G,
1422
+ radar: Z,
1423
+ radialBar: X,
1424
+ treemap: U,
1425
+ table: W,
1426
+ activityGrid: Q,
1423
1427
  kpiNumber: J,
1424
1428
  kpiDelta: ee,
1425
1429
  kpiText: te,
1426
- markdown: ae,
1427
- funnel: ie,
1428
- sankey: oe,
1429
- sunburst: se,
1430
+ markdown: ie,
1431
+ funnel: ae,
1432
+ sankey: se,
1433
+ sunburst: oe,
1430
1434
  heatmap: re,
1431
1435
  retentionHeatmap: ne,
1432
1436
  retentionCombined: le,
1433
1437
  boxPlot: de
1434
1438
  };
1435
- function pe(s, t, a) {
1436
- const i = V[s];
1437
- if (!i)
1439
+ function pe(r, t, i) {
1440
+ const a = V[r];
1441
+ if (!a)
1438
1442
  return { isValid: !0, errors: [] };
1439
- if (i.skipQuery)
1443
+ if (a.skipQuery)
1440
1444
  return { isValid: !0, errors: [] };
1441
1445
  const e = [];
1442
- for (const r of i.dropZones) {
1443
- if (!r.mandatory) continue;
1444
- const n = t?.[r.key];
1446
+ for (const s of a.dropZones) {
1447
+ if (!s.mandatory) continue;
1448
+ const n = t?.[s.key];
1445
1449
  if (!(Array.isArray(n) ? n.length > 0 : !!n)) {
1446
- const c = r.acceptTypes?.join("/") ?? "fields";
1450
+ const m = s.acceptTypes?.join("/") ?? "fields";
1447
1451
  e.push(
1448
- `chartConfig.${r.key} is required for ${s} chart (${r.label}). Accepts: ${c}.`
1452
+ `chartConfig.${s.key} is required for ${r} chart (${s.label}). Accepts: ${m}.`
1449
1453
  );
1450
1454
  }
1451
1455
  }
1452
1456
  return { isValid: e.length === 0, errors: e };
1453
1457
  }
1454
- function ue(s, t, a) {
1455
- const i = V[s];
1456
- if (!i)
1458
+ function ue(r, t, i) {
1459
+ const a = V[r];
1460
+ if (!a)
1457
1461
  return t ?? {};
1458
- const e = { ...t }, r = a.measures ?? [], n = a.dimensions ?? [], c = (a.timeDimensions ?? []).map((l) => l.dimension);
1459
- for (const l of i.dropZones) {
1462
+ const e = { ...t }, s = i.measures ?? [], n = i.dimensions ?? [], m = (i.timeDimensions ?? []).map((l) => l.dimension);
1463
+ for (const l of a.dropZones) {
1460
1464
  const d = e[l.key];
1461
1465
  if (Array.isArray(d) ? d.length > 0 : !!d) continue;
1462
1466
  const y = l.acceptTypes ?? [];
1463
1467
  if (l.key === "sizeField" || l.key === "colorField") {
1464
1468
  if (y.includes("measure")) {
1465
1469
  const x = /* @__PURE__ */ new Set();
1466
- for (const k of i.dropZones) {
1467
- if (k.key === l.key) continue;
1468
- const m = e[k.key];
1469
- Array.isArray(m) ? m.forEach((v) => x.add(v)) : typeof m == "string" && x.add(m);
1470
+ for (const w of a.dropZones) {
1471
+ if (w.key === l.key) continue;
1472
+ const c = e[w.key];
1473
+ Array.isArray(c) ? c.forEach((C) => x.add(C)) : typeof c == "string" && x.add(c);
1470
1474
  }
1471
- const u = r.filter((k) => !x.has(k));
1475
+ const u = s.filter((w) => !x.has(w));
1472
1476
  u.length > 0 && (e[l.key] = u[0]);
1473
1477
  }
1474
1478
  continue;
1475
1479
  }
1476
- const g = [];
1477
- if (y.includes("dimension") && g.push(...n), y.includes("timeDimension") && g.push(...c), y.includes("measure") && g.push(...r), g.length === 0) continue;
1478
- const F = l.maxItems ?? 1 / 0, A = g.slice(0, F);
1479
- A.length > 0 && (e[l.key] = A);
1480
+ const f = [];
1481
+ if (y.includes("dimension") && f.push(...n), y.includes("timeDimension") && f.push(...m), y.includes("measure") && f.push(...s), f.length === 0) continue;
1482
+ const k = l.maxItems ?? 1 / 0, D = f.slice(0, k);
1483
+ D.length > 0 && (e[l.key] = D);
1480
1484
  }
1481
1485
  return e;
1482
1486
  }
1483
- function ce(s) {
1487
+ function me(r) {
1484
1488
  const t = [`
1485
1489
  Chart config requirements by type:`];
1486
- for (const a of s) {
1487
- const i = V[a];
1488
- if (!i) continue;
1489
- const e = i.description ?? "", r = i.useCase ?? "", n = [e, r].filter(Boolean).join(". "), p = n ? ` — ${n}.` : "", c = i.dropZones.filter((d) => d.mandatory);
1490
- if (c.length === 0 && !i.skipQuery) {
1491
- t.push(` ${a}${p} chartConfig auto-inferred from query.`);
1490
+ for (const i of r) {
1491
+ const a = V[i];
1492
+ if (!a) continue;
1493
+ const e = a.description ?? "", s = a.useCase ?? "", n = [e, s].filter(Boolean).join(". "), p = n ? ` — ${n}.` : "", m = a.dropZones.filter((d) => d.mandatory);
1494
+ if (m.length === 0 && !a.skipQuery) {
1495
+ t.push(` ${i}${p} chartConfig auto-inferred from query.`);
1492
1496
  continue;
1493
1497
  }
1494
- if (i.skipQuery) {
1495
- t.push(` ${a}${p} No query needed.`);
1498
+ if (a.skipQuery) {
1499
+ t.push(` ${i}${p} No query needed.`);
1496
1500
  continue;
1497
1501
  }
1498
- const l = c.map((d) => {
1499
- const b = d.acceptTypes?.join("/") ?? "any", y = d.maxItems ? ` (max ${d.maxItems})` : "";
1500
- return `${d.key}=[${b}]${y}`;
1502
+ const l = m.map((d) => {
1503
+ const g = d.acceptTypes?.join("/") ?? "any", y = d.maxItems ? ` (max ${d.maxItems})` : "";
1504
+ return `${d.key}=[${g}]${y}`;
1501
1505
  });
1502
- t.push(` ${a}${p} Requires ${l.join(", ")}.`);
1506
+ t.push(` ${i}${p} Requires ${l.join(", ")}.`);
1503
1507
  }
1504
1508
  return t.join(`
1505
1509
  `);
1506
1510
  }
1507
- const P = [
1511
+ const O = [
1508
1512
  "bar",
1509
1513
  "line",
1510
1514
  "area",
@@ -1523,7 +1527,7 @@ const P = [
1523
1527
  "retentionCombined",
1524
1528
  "boxPlot"
1525
1529
  ];
1526
- function me() {
1530
+ function ce() {
1527
1531
  return [
1528
1532
  // Tool 1: discover_cubes
1529
1533
  {
@@ -1551,7 +1555,7 @@ function me() {
1551
1555
  // Tool 3: execute_query
1552
1556
  {
1553
1557
  name: "execute_query",
1554
- description: "Execute a semantic query and return data results. The query follows the Cube.js query format with measures, dimensions, filters, timeDimensions, order, and limit.",
1558
+ description: "Execute a semantic query and return data results. Supports standard queries (measures/dimensions) and analysis modes (funnel/flow/retention). Only provide ONE mode per call.",
1555
1559
  input_schema: {
1556
1560
  type: "object",
1557
1561
  properties: {
@@ -1598,6 +1602,75 @@ function me() {
1598
1602
  limit: {
1599
1603
  type: "number",
1600
1604
  description: "Row limit"
1605
+ },
1606
+ funnel: {
1607
+ type: "object",
1608
+ properties: {
1609
+ bindingKey: { type: "string", description: 'Entity binding key (e.g., "Events.userId")' },
1610
+ timeDimension: { type: "string", description: 'Time dimension (e.g., "Events.timestamp")' },
1611
+ steps: {
1612
+ type: "array",
1613
+ items: {
1614
+ type: "object",
1615
+ properties: {
1616
+ name: { type: "string" },
1617
+ filter: {},
1618
+ timeToConvert: { type: "string", description: 'ISO 8601 duration (e.g., "P7D")' }
1619
+ },
1620
+ required: ["name"]
1621
+ },
1622
+ description: "Funnel steps (min 2)"
1623
+ },
1624
+ includeTimeMetrics: { type: "boolean" },
1625
+ globalTimeWindow: { type: "string" }
1626
+ },
1627
+ required: ["bindingKey", "timeDimension", "steps"],
1628
+ description: "Funnel analysis config. When provided, measures/dimensions are ignored."
1629
+ },
1630
+ flow: {
1631
+ type: "object",
1632
+ properties: {
1633
+ bindingKey: { type: "string" },
1634
+ timeDimension: { type: "string" },
1635
+ eventDimension: { type: "string", description: "Dimension whose values become node labels" },
1636
+ startingStep: {
1637
+ type: "object",
1638
+ properties: {
1639
+ name: { type: "string" },
1640
+ filter: {}
1641
+ },
1642
+ required: ["name"]
1643
+ },
1644
+ stepsBefore: { type: "number", description: "Steps before starting step (0-5)" },
1645
+ stepsAfter: { type: "number", description: "Steps after starting step (0-5)" },
1646
+ entityLimit: { type: "number" },
1647
+ outputMode: { type: "string", enum: ["sankey", "sunburst"] }
1648
+ },
1649
+ required: ["bindingKey", "timeDimension", "eventDimension", "startingStep"],
1650
+ description: "Flow analysis config. When provided, measures/dimensions are ignored."
1651
+ },
1652
+ retention: {
1653
+ type: "object",
1654
+ properties: {
1655
+ timeDimension: { type: "string" },
1656
+ bindingKey: { type: "string" },
1657
+ dateRange: {
1658
+ type: "object",
1659
+ properties: {
1660
+ start: { type: "string", description: "YYYY-MM-DD" },
1661
+ end: { type: "string", description: "YYYY-MM-DD" }
1662
+ },
1663
+ required: ["start", "end"]
1664
+ },
1665
+ granularity: { type: "string", enum: ["day", "week", "month"] },
1666
+ periods: { type: "number" },
1667
+ retentionType: { type: "string", enum: ["classic", "rolling"] },
1668
+ cohortFilters: {},
1669
+ activityFilters: {},
1670
+ breakdownDimensions: { type: "array", items: { type: "string" } }
1671
+ },
1672
+ required: ["timeDimension", "bindingKey", "dateRange", "granularity", "periods"],
1673
+ description: "Retention analysis config. When provided, measures/dimensions are ignored."
1601
1674
  }
1602
1675
  }
1603
1676
  }
@@ -1606,16 +1679,19 @@ function me() {
1606
1679
  {
1607
1680
  name: "add_portlet",
1608
1681
  description: `Add a chart visualization to the notebook.
1609
- ` + ce(P) + `
1682
+ ` + me(O) + `
1610
1683
  The query is validated before adding. The portlet fetches its own data.`,
1611
1684
  input_schema: {
1612
1685
  type: "object",
1613
1686
  properties: {
1614
1687
  title: { type: "string", description: "Title for the visualization" },
1615
- query: { type: "string", description: "JSON string of the CubeQuery to visualize" },
1688
+ query: {
1689
+ type: "string",
1690
+ description: 'JSON string of the query. Standard: {"measures":[...],"dimensions":[...]}. Funnel: {"funnel":{"bindingKey":"...","timeDimension":"...","steps":[...]}}. Flow: {"flow":{"bindingKey":"...","timeDimension":"...","eventDimension":"...","startingStep":{...}}}. Retention: {"retention":{"timeDimension":"...","bindingKey":"...","dateRange":{"start":"...","end":"..."},"granularity":"...","periods":N}}.'
1691
+ },
1616
1692
  chartType: {
1617
1693
  type: "string",
1618
- enum: P,
1694
+ enum: O,
1619
1695
  description: "Chart type to render"
1620
1696
  },
1621
1697
  chartConfig: {
@@ -1659,29 +1735,31 @@ The query is validated before adding. The portlet fetches its own data.`,
1659
1735
  }
1660
1736
  ];
1661
1737
  }
1662
- function ye(s) {
1663
- const { semanticLayer: t, securityContext: a } = s, i = /* @__PURE__ */ new Map();
1664
- return i.set("discover_cubes", async (e) => {
1665
- const r = await Y(t, {
1738
+ function ye(r) {
1739
+ const { semanticLayer: t, securityContext: i } = r, a = /* @__PURE__ */ new Map();
1740
+ return a.set("discover_cubes", async (e) => {
1741
+ const s = await z(t, {
1666
1742
  topic: e.topic,
1667
1743
  intent: e.intent,
1668
1744
  limit: e.limit,
1669
1745
  minScore: e.minScore
1670
1746
  });
1671
- return { result: JSON.stringify(r, null, 2) };
1672
- }), i.set("get_cube_metadata", async () => {
1747
+ return { result: JSON.stringify(s, null, 2) };
1748
+ }), a.set("get_cube_metadata", async () => {
1673
1749
  const e = t.getMetadata();
1674
1750
  return { result: JSON.stringify(e, null, 2) };
1675
- }), i.set("execute_query", async (e) => {
1751
+ }), a.set("execute_query", async (e) => {
1676
1752
  try {
1677
- const r = {
1753
+ let s;
1754
+ e.funnel ? s = { funnel: e.funnel } : e.flow ? s = { flow: e.flow } : e.retention ? s = { retention: e.retention } : s = {
1678
1755
  measures: e.measures,
1679
1756
  dimensions: e.dimensions,
1680
1757
  filters: e.filters,
1681
1758
  timeDimensions: e.timeDimensions,
1682
1759
  order: e.order,
1683
1760
  limit: e.limit
1684
- }, n = await L(t, a, { query: r });
1761
+ };
1762
+ const n = await M(t, i, { query: s });
1685
1763
  return {
1686
1764
  result: JSON.stringify({
1687
1765
  rowCount: n.data.length,
@@ -1689,13 +1767,13 @@ function ye(s) {
1689
1767
  annotation: n.annotation
1690
1768
  }, null, 2)
1691
1769
  };
1692
- } catch (r) {
1770
+ } catch (s) {
1693
1771
  return {
1694
- result: `Query execution failed: ${r instanceof Error ? r.message : "Unknown error"}`,
1772
+ result: `Query execution failed: ${s instanceof Error ? s.message : "Unknown error"}`,
1695
1773
  isError: !0
1696
1774
  };
1697
1775
  }
1698
- }), i.set("add_portlet", async (e) => {
1776
+ }), a.set("add_portlet", async (e) => {
1699
1777
  const n = {
1700
1778
  number: "kpiNumber",
1701
1779
  retention: "retentionHeatmap"
@@ -1709,48 +1787,55 @@ function ye(s) {
1709
1787
  isError: !0
1710
1788
  };
1711
1789
  }
1712
- const c = t.validateQuery(p);
1713
- if (!c.isValid)
1790
+ const m = t.validateQuery(p);
1791
+ if (!m.isValid)
1714
1792
  return {
1715
1793
  result: `Invalid query — fix these errors and retry:
1716
- ${c.errors.join(`
1794
+ ${m.errors.join(`
1717
1795
  `)}`,
1718
1796
  isError: !0
1719
1797
  };
1720
- const l = ue(n, e.chartConfig, p), d = pe(n, l);
1721
- if (!d.isValid)
1722
- return {
1723
- result: `Chart config invalid — fix these errors and retry:
1724
- ${d.errors.join(`
1798
+ const l = !!(p.funnel || p.flow || p.retention);
1799
+ let d;
1800
+ if (l)
1801
+ d = e.chartConfig ?? {};
1802
+ else {
1803
+ const f = ue(n, e.chartConfig, p), k = pe(n, f);
1804
+ if (!k.isValid)
1805
+ return {
1806
+ result: `Chart config invalid — fix these errors and retry:
1807
+ ${k.errors.join(`
1725
1808
  `)}`,
1726
- isError: !0
1727
- };
1728
- const b = `portlet-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, y = {
1729
- id: b,
1809
+ isError: !0
1810
+ };
1811
+ d = f;
1812
+ }
1813
+ const g = `portlet-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, y = {
1814
+ id: g,
1730
1815
  title: e.title,
1731
1816
  query: e.query,
1732
1817
  chartType: n,
1733
- chartConfig: l,
1818
+ chartConfig: d,
1734
1819
  displayConfig: e.displayConfig
1735
1820
  };
1736
1821
  return {
1737
- result: `Portlet "${e.title}" added to notebook (id: ${b}, chart: ${n}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
1822
+ result: `Portlet "${e.title}" added to notebook (id: ${g}, chart: ${n}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
1738
1823
  sideEffect: { type: "add_portlet", data: y }
1739
1824
  };
1740
- }), i.set("add_markdown", async (e) => {
1741
- const r = `markdown-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, n = {
1742
- id: r,
1825
+ }), a.set("add_markdown", async (e) => {
1826
+ const s = `markdown-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, n = {
1827
+ id: s,
1743
1828
  title: e.title,
1744
1829
  content: e.content
1745
1830
  };
1746
1831
  return {
1747
- result: `Markdown block added to notebook (id: ${r}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
1832
+ result: `Markdown block added to notebook (id: ${s}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
1748
1833
  sideEffect: { type: "add_markdown", data: n }
1749
1834
  };
1750
- }), i;
1835
+ }), a;
1751
1836
  }
1752
- async function* be(s) {
1753
- const { message: t, sessionId: a, semanticLayer: i, securityContext: e, agentConfig: r, apiKey: n } = s;
1837
+ async function* be(r) {
1838
+ const { message: t, sessionId: i, semanticLayer: a, securityContext: e, agentConfig: s, apiKey: n } = r;
1754
1839
  let p;
1755
1840
  try {
1756
1841
  const u = await import(
@@ -1767,104 +1852,104 @@ async function* be(s) {
1767
1852
  };
1768
1853
  return;
1769
1854
  }
1770
- const c = new p({ apiKey: n }), l = me(), d = ye({ semanticLayer: i, securityContext: e }), b = i.getMetadata(), y = R(b), g = r.model || "claude-sonnet-4-6", F = r.maxTurns || 25, A = r.maxTokens || 4096, x = [
1855
+ const m = new p({ apiKey: n }), l = ce(), d = ye({ semanticLayer: a, securityContext: e }), g = a.getMetadata(), y = L(g), f = s.model || "claude-sonnet-4-6", k = s.maxTurns || 25, D = s.maxTokens || 4096, x = [
1771
1856
  { role: "user", content: t }
1772
1857
  ];
1773
1858
  try {
1774
- for (let u = 0; u < F; u++) {
1775
- const k = await c.messages.create({
1776
- model: g,
1777
- max_tokens: A,
1859
+ for (let u = 0; u < k; u++) {
1860
+ const w = await m.messages.create({
1861
+ model: f,
1862
+ max_tokens: D,
1778
1863
  system: y,
1779
1864
  tools: l,
1780
1865
  messages: x,
1781
1866
  stream: !0
1782
- }), m = [];
1783
- let v = -1, C = "", _ = "";
1784
- for await (const f of k)
1785
- switch (f.type) {
1867
+ }), c = [];
1868
+ let C = -1, T = "", _ = "";
1869
+ for await (const h of w)
1870
+ switch (h.type) {
1786
1871
  case "content_block_start": {
1787
- v++;
1788
- const o = f.content_block;
1789
- o.type === "tool_use" ? (m.push({ type: "tool_use", id: o.id, name: o.name, input: {} }), C = "", yield {
1872
+ C++;
1873
+ const o = h.content_block;
1874
+ o.type === "tool_use" ? (c.push({ type: "tool_use", id: o.id, name: o.name, input: {} }), T = "", yield {
1790
1875
  type: "tool_use_start",
1791
1876
  data: { id: o.id, name: o.name, input: void 0 }
1792
- }) : o.type === "text" && m.push({ type: "text", text: "" });
1877
+ }) : o.type === "text" && c.push({ type: "text", text: "" });
1793
1878
  break;
1794
1879
  }
1795
1880
  case "content_block_delta": {
1796
- const o = f.delta;
1881
+ const o = h.delta;
1797
1882
  if (o.type === "text_delta" && o.text) {
1798
- const T = m[v];
1799
- T && (T.text = (T.text || "") + o.text), yield { type: "text_delta", data: o.text };
1800
- } else o.type === "input_json_delta" && o.partial_json && (C += o.partial_json);
1883
+ const A = c[C];
1884
+ A && (A.text = (A.text || "") + o.text), yield { type: "text_delta", data: o.text };
1885
+ } else o.type === "input_json_delta" && o.partial_json && (T += o.partial_json);
1801
1886
  break;
1802
1887
  }
1803
1888
  case "content_block_stop": {
1804
- const o = m[v];
1805
- if (o?.type === "tool_use" && C) {
1889
+ const o = c[C];
1890
+ if (o?.type === "tool_use" && T) {
1806
1891
  try {
1807
- o.input = JSON.parse(C);
1892
+ o.input = JSON.parse(T);
1808
1893
  } catch {
1809
1894
  o.input = {};
1810
1895
  }
1811
- C = "";
1896
+ T = "";
1812
1897
  }
1813
1898
  break;
1814
1899
  }
1815
1900
  case "message_delta": {
1816
- const o = f.delta;
1901
+ const o = h.delta;
1817
1902
  o.stop_reason && (_ = o.stop_reason);
1818
1903
  break;
1819
1904
  }
1820
1905
  }
1821
- if (x.push({ role: "assistant", content: m }), _ !== "tool_use")
1906
+ if (x.push({ role: "assistant", content: c }), _ !== "tool_use")
1822
1907
  break;
1823
- const D = [];
1824
- for (const f of m) {
1825
- if (f.type !== "tool_use") continue;
1826
- const o = f.name, T = f.input || {}, w = f.id, I = d.get(o);
1908
+ const S = [];
1909
+ for (const h of c) {
1910
+ if (h.type !== "tool_use") continue;
1911
+ const o = h.name, A = h.input || {}, v = h.id, I = d.get(o);
1827
1912
  if (!I) {
1828
- D.push({
1913
+ S.push({
1829
1914
  type: "tool_result",
1830
- tool_use_id: w,
1915
+ tool_use_id: v,
1831
1916
  content: `Unknown tool: ${o}`,
1832
1917
  is_error: !0
1833
1918
  }), yield {
1834
1919
  type: "tool_use_result",
1835
- data: { id: w, name: o, result: `Unknown tool: ${o}` }
1920
+ data: { id: v, name: o, result: `Unknown tool: ${o}` }
1836
1921
  };
1837
1922
  continue;
1838
1923
  }
1839
1924
  try {
1840
- const h = await I(T);
1841
- h.sideEffect && (yield h.sideEffect), D.push({
1925
+ const b = await I(A);
1926
+ b.sideEffect && (yield b.sideEffect), S.push({
1842
1927
  type: "tool_result",
1843
- tool_use_id: w,
1844
- content: h.result,
1845
- ...h.isError ? { is_error: !0 } : {}
1928
+ tool_use_id: v,
1929
+ content: b.result,
1930
+ ...b.isError ? { is_error: !0 } : {}
1846
1931
  }), yield {
1847
1932
  type: "tool_use_result",
1848
- data: { id: w, name: o, result: h.result }
1933
+ data: { id: v, name: o, result: b.result }
1849
1934
  };
1850
- } catch (h) {
1851
- const O = h instanceof Error ? h.message : "Tool execution failed";
1852
- D.push({
1935
+ } catch (b) {
1936
+ const E = b instanceof Error ? b.message : "Tool execution failed";
1937
+ S.push({
1853
1938
  type: "tool_result",
1854
- tool_use_id: w,
1855
- content: O,
1939
+ tool_use_id: v,
1940
+ content: E,
1856
1941
  is_error: !0
1857
1942
  }), yield {
1858
1943
  type: "tool_use_result",
1859
- data: { id: w, name: o, result: O }
1944
+ data: { id: v, name: o, result: E }
1860
1945
  };
1861
1946
  }
1862
1947
  }
1863
- yield { type: "turn_complete", data: {} }, x.push({ role: "user", content: D });
1948
+ yield { type: "turn_complete", data: {} }, x.push({ role: "user", content: S });
1864
1949
  }
1865
1950
  yield {
1866
1951
  type: "done",
1867
- data: { sessionId: a || "" }
1952
+ data: { sessionId: i || "" }
1868
1953
  };
1869
1954
  } catch (u) {
1870
1955
  yield {