drizzle-cube 0.4.9 → 0.4.11
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/dist/adapters/express/index.cjs +1 -1
- package/dist/adapters/express/index.js +2 -2
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/fastify/index.js +2 -2
- package/dist/adapters/{handler-CSHsefnC.js → handler-CQkIwtxp.js} +251 -178
- package/dist/adapters/{handler-Xe_2ItOo.cjs → handler-dnkqpznh.cjs} +13 -13
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/hono/index.js +2 -2
- package/dist/adapters/{mcp-transport-KX92EgkF.cjs → mcp-transport-8u9G5oNa.cjs} +9 -9
- package/dist/adapters/{mcp-transport-CU5g9bxj.js → mcp-transport-m1X1GtwG.js} +13 -4
- package/dist/adapters/nextjs/index.cjs +2 -2
- package/dist/adapters/nextjs/index.js +2 -2
- package/dist/client/charts.js +4 -4
- package/dist/client/chunks/{analysis-builder-DFt9p8tj.js → analysis-builder-BMmWeFPr.js} +4 -4
- package/dist/client/chunks/{analysis-builder-DFt9p8tj.js.map → analysis-builder-BMmWeFPr.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-shared-DOHV2W8A.js → analysis-builder-shared-D56zYeV0.js} +2 -2
- package/dist/client/chunks/{analysis-builder-shared-DOHV2W8A.js.map → analysis-builder-shared-D56zYeV0.js.map} +1 -1
- package/dist/client/chunks/{chart-area-QKKboTbq.js → chart-area-BJAgusst.js} +2 -2
- package/dist/client/chunks/{chart-area-QKKboTbq.js.map → chart-area-BJAgusst.js.map} +1 -1
- package/dist/client/chunks/chart-bar-Blypx8O4.js +267 -0
- package/dist/client/chunks/chart-bar-Blypx8O4.js.map +1 -0
- package/dist/client/chunks/{chart-line-C7YcMWBw.js → chart-line-zi6olZet.js} +2 -2
- package/dist/client/chunks/{chart-line-C7YcMWBw.js.map → chart-line-zi6olZet.js.map} +1 -1
- package/dist/client/chunks/{charts-loader-HYQFVOo4.js → charts-loader-CH0_S06T.js} +4 -4
- package/dist/client/chunks/{charts-loader-HYQFVOo4.js.map → charts-loader-CH0_S06T.js.map} +1 -1
- package/dist/client/chunks/{components-8FAXo62Z.js → components-ClQziOcT.js} +3 -3
- package/dist/client/chunks/{components-8FAXo62Z.js.map → components-ClQziOcT.js.map} +1 -1
- package/dist/client/components.js +1 -1
- package/dist/client/hooks/useAgentChat.d.ts +1 -1
- package/dist/client/index.js +443 -413
- package/dist/client/index.js.map +1 -1
- package/dist/client/stores/notebookStore.d.ts +3 -0
- package/dist/client/utils.js +1 -1
- package/dist/client-bundle-stats.html +1 -1
- package/dist/server/index.cjs +16 -16
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +161 -79
- package/package.json +1 -1
- package/dist/client/chunks/chart-bar-HpXF42H1.js +0 -254
- package/dist/client/chunks/chart-bar-HpXF42H1.js.map +0 -1
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import { h as
|
|
2
|
-
import { handleDiscover as
|
|
3
|
-
function
|
|
4
|
-
if (
|
|
1
|
+
import { h as N, Q as P, j as O, D as R } from "./mcp-transport-m1X1GtwG.js";
|
|
2
|
+
import { handleDiscover as Y, handleLoad as M } from "./utils.js";
|
|
3
|
+
function z(o) {
|
|
4
|
+
if (o.length === 0)
|
|
5
5
|
return "No cubes are currently available.";
|
|
6
6
|
const t = ["## Available Cubes", ""];
|
|
7
|
-
for (const i of
|
|
7
|
+
for (const i of o) {
|
|
8
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
|
|
11
|
-
const e =
|
|
12
|
-
t.push(`- \`${i.name}.${
|
|
10
|
+
for (const s of i.measures) {
|
|
11
|
+
const e = s.description ? ` - ${s.description}` : "";
|
|
12
|
+
t.push(`- \`${i.name}.${s.name}\` (${s.type})${e}`);
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
if (i.dimensions && i.dimensions.length > 0) {
|
|
16
16
|
t.push(""), t.push("**Dimensions:**");
|
|
17
|
-
for (const
|
|
18
|
-
const e =
|
|
19
|
-
t.push(`- \`${i.name}.${
|
|
17
|
+
for (const s of i.dimensions) {
|
|
18
|
+
const e = s.description ? ` - ${s.description}` : "";
|
|
19
|
+
t.push(`- \`${i.name}.${s.name}\` (${s.type})${e}`);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
if (i.relationships && i.relationships.length > 0) {
|
|
23
23
|
t.push(""), t.push("**Joins:**");
|
|
24
|
-
for (const
|
|
25
|
-
t.push(`- → \`${
|
|
24
|
+
for (const s of i.relationships)
|
|
25
|
+
t.push(`- → \`${s.targetCube}\` (${s.relationship})`);
|
|
26
26
|
}
|
|
27
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
|
|
33
|
-
return
|
|
32
|
+
function S(o) {
|
|
33
|
+
return o.messages.map((t) => t.content.text).join(`
|
|
34
34
|
|
|
35
35
|
`);
|
|
36
36
|
}
|
|
37
|
-
function L(
|
|
37
|
+
function L(o) {
|
|
38
38
|
return [
|
|
39
39
|
"# Drizzle Cube Analytics Agent",
|
|
40
40
|
"",
|
|
@@ -52,6 +52,7 @@ function L(r) {
|
|
|
52
52
|
"## Important Guidelines",
|
|
53
53
|
"",
|
|
54
54
|
"- ALWAYS discover cubes first before attempting queries",
|
|
55
|
+
"- Field names MUST be `CubeName.fieldName` (e.g. `PullRequests.count`, `Teams.name`). NEVER use just the cube name as a field — `PullRequests.PullRequests` is WRONG.",
|
|
55
56
|
"- Use `add_portlet` to create visualizations after getting query results",
|
|
56
57
|
"- Use `add_markdown` to explain your findings, methodology, and insights",
|
|
57
58
|
"- Choose appropriate chart types: bar for categories, line for trends, table for detailed data",
|
|
@@ -63,15 +64,20 @@ function L(r) {
|
|
|
63
64
|
"### CRITICAL: Always think before acting",
|
|
64
65
|
"- EVERY single turn MUST begin with a text message (1-2 sentences) BEFORE any tool calls. This is your #1 rule — never violate it.",
|
|
65
66
|
"- This applies to EVERY turn, including turns where you are adding visualizations or explanations to the notebook.",
|
|
66
|
-
`- Even when adding multiple
|
|
67
|
-
'- Example good turn: "Let me
|
|
68
|
-
`- Example good turn: "I'll add a
|
|
67
|
+
`- Even when adding multiple charts in sequence, each turn must start with a brief status like "Now I'll chart the productivity breakdown." or "Next, let me show the department comparison."`,
|
|
68
|
+
'- Example good turn: "Let me see what data is available." → discover_cubes',
|
|
69
|
+
`- Example good turn: "I'll add a chart showing the top employees." → add_markdown → add_portlet`,
|
|
69
70
|
"- Example bad turn: (no text) → add_portlet ← NEVER do this",
|
|
70
71
|
"",
|
|
71
72
|
"### Text vs Notebook",
|
|
72
73
|
"- ALL analysis, findings, methodology, and insights MUST go through `add_markdown` tool calls — never in your text responses",
|
|
73
74
|
"- Your text responses must be 1-2 short sentences (under 50 words) summarizing what you are about to do next — status updates only",
|
|
74
75
|
"- Never use markdown formatting (headers, bullets, bold, code blocks) in text responses — plain sentences only",
|
|
76
|
+
"- Write text responses as a friendly analyst would — use plain business language the user understands",
|
|
77
|
+
'- NEVER mention internal terms like "cube", "query syntax", "field names", "measures", "dimensions", "portlet", "prefix format", or tool names in text responses',
|
|
78
|
+
'- Instead of "Let me correct the query syntax and retry" → "Let me fix that and try again"',
|
|
79
|
+
`- Instead of "I'll query the PullRequests cube" → "I'll look at the pull request data"`,
|
|
80
|
+
`- Instead of "Adding a portlet with the results" → "Here's a chart of the results"`,
|
|
75
81
|
"",
|
|
76
82
|
"### Notebook content rules",
|
|
77
83
|
"- Before each `add_portlet`, ALWAYS call `add_markdown` first to explain WHY you are adding this visualization and what it shows",
|
|
@@ -111,6 +117,21 @@ function L(r) {
|
|
|
111
117
|
"",
|
|
112
118
|
'**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`.',
|
|
113
119
|
"",
|
|
120
|
+
"## Chart Axis Configuration Rules",
|
|
121
|
+
"",
|
|
122
|
+
"**Bar charts MUST have an xAxis.** Put a dimension in `chartConfig.xAxis` so bars have category labels. If your query has no dimensions, add one or use `table` instead.",
|
|
123
|
+
"",
|
|
124
|
+
"**Never duplicate xAxis in series.** Putting the same dimension in both `xAxis` and `series` creates a sparse, broken-looking chart. The `series` field is ONLY for splitting bars into grouped/stacked sub-series by a SECOND dimension.",
|
|
125
|
+
"",
|
|
126
|
+
"Correct bar chart examples:",
|
|
127
|
+
'- Categories only: `xAxis: ["Cube.category"], yAxis: ["Cube.count"]` — no series needed',
|
|
128
|
+
'- Grouped bars: `xAxis: ["Cube.category"], yAxis: ["Cube.count"], series: ["Cube.status"]` — series is a DIFFERENT dimension',
|
|
129
|
+
'- Multiple measures: `xAxis: ["Cube.category"], yAxis: ["Cube.count", "Cube.total"]` — each measure becomes a bar group',
|
|
130
|
+
"",
|
|
131
|
+
"Wrong:",
|
|
132
|
+
'- `xAxis: [], yAxis: ["Cube.avg1", "Cube.avg2"]` — missing xAxis, bars have no labels',
|
|
133
|
+
'- `xAxis: ["Cube.size"], series: ["Cube.size"]` — same field in both, creates sparse chart',
|
|
134
|
+
"",
|
|
114
135
|
"## Analysis Mode Decision Tree",
|
|
115
136
|
"",
|
|
116
137
|
"The default mode is **query** (standard measures/dimensions). Switch to a special mode only when the user's question matches:",
|
|
@@ -139,23 +160,23 @@ function L(r) {
|
|
|
139
160
|
"",
|
|
140
161
|
"---",
|
|
141
162
|
"",
|
|
142
|
-
|
|
163
|
+
S(N),
|
|
143
164
|
"",
|
|
144
165
|
"---",
|
|
145
166
|
"",
|
|
146
|
-
|
|
167
|
+
S(P),
|
|
147
168
|
"",
|
|
148
169
|
"---",
|
|
149
170
|
"",
|
|
150
|
-
|
|
171
|
+
S(O),
|
|
151
172
|
"",
|
|
152
173
|
"---",
|
|
153
174
|
"",
|
|
154
|
-
|
|
175
|
+
S(R),
|
|
155
176
|
"",
|
|
156
177
|
"---",
|
|
157
178
|
"",
|
|
158
|
-
|
|
179
|
+
z(o)
|
|
159
180
|
].join(`
|
|
160
181
|
`);
|
|
161
182
|
}
|
|
@@ -414,7 +435,7 @@ const H = {
|
|
|
414
435
|
description: "Number formatting for values"
|
|
415
436
|
}
|
|
416
437
|
]
|
|
417
|
-
},
|
|
438
|
+
}, G = {
|
|
418
439
|
label: "Scatter Plot",
|
|
419
440
|
description: "Reveal correlations between variables",
|
|
420
441
|
useCase: "Best for identifying patterns, correlations, outliers, and relationships between two measures",
|
|
@@ -462,7 +483,7 @@ const H = {
|
|
|
462
483
|
description: "Number formatting for Y-axis"
|
|
463
484
|
}
|
|
464
485
|
]
|
|
465
|
-
},
|
|
486
|
+
}, K = {
|
|
466
487
|
label: "Bubble Chart",
|
|
467
488
|
description: "Compare three dimensions of data",
|
|
468
489
|
useCase: "Best for showing relationships between three variables (X, Y, and size), market analysis",
|
|
@@ -664,7 +685,7 @@ const H = {
|
|
|
664
685
|
description: "Number formatting for numeric values"
|
|
665
686
|
}
|
|
666
687
|
]
|
|
667
|
-
},
|
|
688
|
+
}, J = {
|
|
668
689
|
label: "Activity Grid",
|
|
669
690
|
description: "GitHub-style activity grid showing temporal patterns across different time scales",
|
|
670
691
|
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",
|
|
@@ -698,8 +719,8 @@ const H = {
|
|
|
698
719
|
description: "Automatically size blocks to fill portlet width and height while maintaining aspect ratio"
|
|
699
720
|
}
|
|
700
721
|
],
|
|
701
|
-
validate: (
|
|
702
|
-
const { dateField: t, valueField: i } =
|
|
722
|
+
validate: (o) => {
|
|
723
|
+
const { dateField: t, valueField: i } = o;
|
|
703
724
|
return !t || Array.isArray(t) && t.length === 0 ? {
|
|
704
725
|
isValid: !1,
|
|
705
726
|
message: "Time dimension is required for activity grid"
|
|
@@ -709,7 +730,7 @@ const H = {
|
|
|
709
730
|
} : { isValid: !0 };
|
|
710
731
|
},
|
|
711
732
|
clickableElements: { cell: !0 }
|
|
712
|
-
},
|
|
733
|
+
}, Q = {
|
|
713
734
|
label: "KPI Number",
|
|
714
735
|
description: "Display key performance indicators as large numbers",
|
|
715
736
|
useCase: "Perfect for showing important metrics like revenue, user count, or other key business metrics in a prominent, easy-to-read format",
|
|
@@ -867,7 +888,7 @@ const H = {
|
|
|
867
888
|
}
|
|
868
889
|
],
|
|
869
890
|
displayOptions: ["hideHeader"],
|
|
870
|
-
validate: (
|
|
891
|
+
validate: (o) => !o.yAxis || Array.isArray(o.yAxis) && o.yAxis.length === 0 ? {
|
|
871
892
|
isValid: !1,
|
|
872
893
|
message: "A measure is required for KPI Delta charts"
|
|
873
894
|
} : { isValid: !0 }
|
|
@@ -1005,7 +1026,7 @@ Use --- for horizontal rules.`,
|
|
|
1005
1026
|
description: "Add an accent-colored border on one side of the content"
|
|
1006
1027
|
}
|
|
1007
1028
|
]
|
|
1008
|
-
},
|
|
1029
|
+
}, se = {
|
|
1009
1030
|
label: "Funnel Chart",
|
|
1010
1031
|
description: "Show conversion through sequential steps",
|
|
1011
1032
|
useCase: "Best for visualizing user journey funnels, sales pipelines, or multi-step processes",
|
|
@@ -1092,7 +1113,7 @@ Use --- for horizontal rules.`,
|
|
|
1092
1113
|
description: "Display 90th percentile time to convert"
|
|
1093
1114
|
}
|
|
1094
1115
|
]
|
|
1095
|
-
},
|
|
1116
|
+
}, ae = {
|
|
1096
1117
|
label: "Sankey Chart",
|
|
1097
1118
|
description: "Show flow between states or steps",
|
|
1098
1119
|
useCase: "Best for visualizing user journey flows, path analysis, or state transitions",
|
|
@@ -1264,7 +1285,7 @@ Use --- for horizontal rules.`,
|
|
|
1264
1285
|
description: "Number formatting for cell values and legend"
|
|
1265
1286
|
}
|
|
1266
1287
|
],
|
|
1267
|
-
validate: (
|
|
1288
|
+
validate: (o) => o.xAxis?.length ? o.yAxis?.length ? o.valueField?.length ? { isValid: !0 } : { isValid: !1, message: "Value measure required" } : { isValid: !1, message: "Y-axis dimension required" } : { isValid: !1, message: "X-axis dimension required" }
|
|
1268
1289
|
}, ne = {
|
|
1269
1290
|
label: "Retention Matrix",
|
|
1270
1291
|
// RetentionHeatmap auto-configures from the retention data structure
|
|
@@ -1412,103 +1433,129 @@ Use --- for horizontal rules.`,
|
|
|
1412
1433
|
description: "Number formatting for the value axis"
|
|
1413
1434
|
}
|
|
1414
1435
|
]
|
|
1415
|
-
},
|
|
1436
|
+
}, _ = {
|
|
1416
1437
|
bar: H,
|
|
1417
1438
|
line: $,
|
|
1418
1439
|
area: B,
|
|
1419
1440
|
pie: j,
|
|
1420
|
-
scatter:
|
|
1421
|
-
bubble:
|
|
1441
|
+
scatter: G,
|
|
1442
|
+
bubble: K,
|
|
1422
1443
|
radar: Z,
|
|
1423
1444
|
radialBar: X,
|
|
1424
1445
|
treemap: U,
|
|
1425
1446
|
table: W,
|
|
1426
|
-
activityGrid:
|
|
1427
|
-
kpiNumber:
|
|
1447
|
+
activityGrid: J,
|
|
1448
|
+
kpiNumber: Q,
|
|
1428
1449
|
kpiDelta: ee,
|
|
1429
1450
|
kpiText: te,
|
|
1430
1451
|
markdown: ie,
|
|
1431
|
-
funnel:
|
|
1432
|
-
sankey:
|
|
1452
|
+
funnel: se,
|
|
1453
|
+
sankey: ae,
|
|
1433
1454
|
sunburst: oe,
|
|
1434
1455
|
heatmap: re,
|
|
1435
1456
|
retentionHeatmap: ne,
|
|
1436
1457
|
retentionCombined: le,
|
|
1437
1458
|
boxPlot: de
|
|
1438
1459
|
};
|
|
1439
|
-
function pe(
|
|
1440
|
-
const
|
|
1441
|
-
if (!
|
|
1460
|
+
function pe(o, t, i) {
|
|
1461
|
+
const s = _[o];
|
|
1462
|
+
if (!s)
|
|
1442
1463
|
return { isValid: !0, errors: [] };
|
|
1443
|
-
if (
|
|
1464
|
+
if (s.skipQuery)
|
|
1444
1465
|
return { isValid: !0, errors: [] };
|
|
1445
1466
|
const e = [];
|
|
1446
|
-
for (const
|
|
1447
|
-
if (!
|
|
1448
|
-
const n = t?.[
|
|
1467
|
+
for (const a of s.dropZones) {
|
|
1468
|
+
if (!a.mandatory) continue;
|
|
1469
|
+
const n = t?.[a.key];
|
|
1449
1470
|
if (!(Array.isArray(n) ? n.length > 0 : !!n)) {
|
|
1450
|
-
const
|
|
1471
|
+
const u = a.acceptTypes?.join("/") ?? "fields";
|
|
1451
1472
|
e.push(
|
|
1452
|
-
`chartConfig.${
|
|
1473
|
+
`chartConfig.${a.key} is required for ${o} chart (${a.label}). Accepts: ${u}.`
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
if (o === "bar") {
|
|
1478
|
+
const a = t?.xAxis;
|
|
1479
|
+
if (!(Array.isArray(a) ? a.length > 0 : !!a)) {
|
|
1480
|
+
const l = i.dimensions ?? [], u = i.timeDimensions ?? [];
|
|
1481
|
+
l.length > 0 || u.length > 0 ? e.push(
|
|
1482
|
+
"chartConfig.xAxis is required for bar charts. Put a dimension in xAxis so bars have category labels."
|
|
1483
|
+
) : e.push(
|
|
1484
|
+
'Bar charts need an xAxis dimension for category labels. Add a dimension to the query or use "table" chart type instead.'
|
|
1453
1485
|
);
|
|
1454
1486
|
}
|
|
1455
1487
|
}
|
|
1488
|
+
if (t?.xAxis && t?.series) {
|
|
1489
|
+
const a = new Set(
|
|
1490
|
+
Array.isArray(t.xAxis) ? t.xAxis : [t.xAxis]
|
|
1491
|
+
), l = (Array.isArray(t.series) ? t.series : [t.series]).filter((u) => a.has(u));
|
|
1492
|
+
l.length > 0 && e.push(
|
|
1493
|
+
`chartConfig.series must not contain the same field as xAxis (found: ${l.join(", ")}). The series field is only for splitting into grouped/stacked sub-series by a DIFFERENT dimension. Remove the duplicate from series.`
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1456
1496
|
return { isValid: e.length === 0, errors: e };
|
|
1457
1497
|
}
|
|
1458
|
-
function ue(
|
|
1459
|
-
const
|
|
1460
|
-
if (!
|
|
1498
|
+
function ue(o, t, i) {
|
|
1499
|
+
const s = _[o];
|
|
1500
|
+
if (!s)
|
|
1461
1501
|
return t ?? {};
|
|
1462
|
-
const e = { ...t },
|
|
1463
|
-
for (const
|
|
1464
|
-
const
|
|
1465
|
-
if (Array.isArray(
|
|
1466
|
-
const
|
|
1467
|
-
if (
|
|
1468
|
-
if (
|
|
1469
|
-
const
|
|
1470
|
-
for (const
|
|
1471
|
-
if (
|
|
1472
|
-
const
|
|
1473
|
-
Array.isArray(
|
|
1502
|
+
const e = { ...t }, a = i.measures ?? [], n = i.dimensions ?? [], u = (i.timeDimensions ?? []).map((d) => d.dimension);
|
|
1503
|
+
for (const d of s.dropZones) {
|
|
1504
|
+
const p = e[d.key];
|
|
1505
|
+
if (Array.isArray(p) ? p.length > 0 : !!p) continue;
|
|
1506
|
+
const f = d.acceptTypes ?? [];
|
|
1507
|
+
if (d.key === "sizeField" || d.key === "colorField") {
|
|
1508
|
+
if (f.includes("measure")) {
|
|
1509
|
+
const m = /* @__PURE__ */ new Set();
|
|
1510
|
+
for (const y of s.dropZones) {
|
|
1511
|
+
if (y.key === d.key) continue;
|
|
1512
|
+
const x = e[y.key];
|
|
1513
|
+
Array.isArray(x) ? x.forEach((w) => m.add(w)) : typeof x == "string" && m.add(x);
|
|
1474
1514
|
}
|
|
1475
|
-
const
|
|
1476
|
-
|
|
1515
|
+
const C = a.filter((y) => !m.has(y));
|
|
1516
|
+
C.length > 0 && (e[d.key] = C[0]);
|
|
1477
1517
|
}
|
|
1478
1518
|
continue;
|
|
1479
1519
|
}
|
|
1480
|
-
const
|
|
1481
|
-
if (
|
|
1482
|
-
|
|
1483
|
-
|
|
1520
|
+
const c = [];
|
|
1521
|
+
if (f.includes("dimension") && c.push(...n), f.includes("timeDimension") && c.push(...u), f.includes("measure") && c.push(...a), c.length === 0) continue;
|
|
1522
|
+
let g = c;
|
|
1523
|
+
if (d.key === "series") {
|
|
1524
|
+
const m = new Set(
|
|
1525
|
+
Array.isArray(e.xAxis) ? e.xAxis : e.xAxis ? [e.xAxis] : []
|
|
1526
|
+
);
|
|
1527
|
+
if (g = c.filter((C) => !m.has(C)), g.length === 0) continue;
|
|
1528
|
+
}
|
|
1529
|
+
const F = d.maxItems ?? 1 / 0, v = g.slice(0, F);
|
|
1530
|
+
v.length > 0 && (e[d.key] = v);
|
|
1484
1531
|
}
|
|
1485
1532
|
return e;
|
|
1486
1533
|
}
|
|
1487
|
-
function me(
|
|
1534
|
+
function me(o) {
|
|
1488
1535
|
const t = [`
|
|
1489
1536
|
Chart config requirements by type:`];
|
|
1490
|
-
for (const i of
|
|
1491
|
-
const
|
|
1492
|
-
if (!
|
|
1493
|
-
const e =
|
|
1494
|
-
if (
|
|
1495
|
-
t.push(` ${i}${
|
|
1537
|
+
for (const i of o) {
|
|
1538
|
+
const s = _[i];
|
|
1539
|
+
if (!s) continue;
|
|
1540
|
+
const e = s.description ?? "", a = s.useCase ?? "", n = [e, a].filter(Boolean).join(". "), l = n ? ` — ${n}.` : "", u = s.dropZones.filter((p) => p.mandatory);
|
|
1541
|
+
if (u.length === 0 && !s.skipQuery) {
|
|
1542
|
+
t.push(` ${i}${l} chartConfig auto-inferred from query.`);
|
|
1496
1543
|
continue;
|
|
1497
1544
|
}
|
|
1498
|
-
if (
|
|
1499
|
-
t.push(` ${i}${
|
|
1545
|
+
if (s.skipQuery) {
|
|
1546
|
+
t.push(` ${i}${l} No query needed.`);
|
|
1500
1547
|
continue;
|
|
1501
1548
|
}
|
|
1502
|
-
const
|
|
1503
|
-
const
|
|
1504
|
-
return `${
|
|
1549
|
+
const d = u.map((p) => {
|
|
1550
|
+
const k = p.acceptTypes?.join("/") ?? "any", f = p.maxItems ? ` (max ${p.maxItems})` : "";
|
|
1551
|
+
return `${p.key}=[${k}]${f}`;
|
|
1505
1552
|
});
|
|
1506
|
-
t.push(` ${i}${
|
|
1553
|
+
t.push(` ${i}${l} Requires ${d.join(", ")}.`);
|
|
1507
1554
|
}
|
|
1508
1555
|
return t.join(`
|
|
1509
1556
|
`);
|
|
1510
1557
|
}
|
|
1511
|
-
const
|
|
1558
|
+
const q = [
|
|
1512
1559
|
"bar",
|
|
1513
1560
|
"line",
|
|
1514
1561
|
"area",
|
|
@@ -1679,7 +1726,7 @@ function ce() {
|
|
|
1679
1726
|
{
|
|
1680
1727
|
name: "add_portlet",
|
|
1681
1728
|
description: `Add a chart visualization to the notebook.
|
|
1682
|
-
` + me(
|
|
1729
|
+
` + me(q) + `
|
|
1683
1730
|
The query is validated before adding. The portlet fetches its own data.`,
|
|
1684
1731
|
input_schema: {
|
|
1685
1732
|
type: "object",
|
|
@@ -1691,7 +1738,7 @@ The query is validated before adding. The portlet fetches its own data.`,
|
|
|
1691
1738
|
},
|
|
1692
1739
|
chartType: {
|
|
1693
1740
|
type: "string",
|
|
1694
|
-
enum:
|
|
1741
|
+
enum: q,
|
|
1695
1742
|
description: "Chart type to render"
|
|
1696
1743
|
},
|
|
1697
1744
|
chartConfig: {
|
|
@@ -1735,23 +1782,23 @@ The query is validated before adding. The portlet fetches its own data.`,
|
|
|
1735
1782
|
}
|
|
1736
1783
|
];
|
|
1737
1784
|
}
|
|
1738
|
-
function ye(
|
|
1739
|
-
const { semanticLayer: t, securityContext: i } =
|
|
1740
|
-
return
|
|
1741
|
-
const
|
|
1785
|
+
function ye(o) {
|
|
1786
|
+
const { semanticLayer: t, securityContext: i } = o, s = /* @__PURE__ */ new Map();
|
|
1787
|
+
return s.set("discover_cubes", async (e) => {
|
|
1788
|
+
const a = await Y(t, {
|
|
1742
1789
|
topic: e.topic,
|
|
1743
1790
|
intent: e.intent,
|
|
1744
1791
|
limit: e.limit,
|
|
1745
1792
|
minScore: e.minScore
|
|
1746
1793
|
});
|
|
1747
|
-
return { result: JSON.stringify(
|
|
1748
|
-
}),
|
|
1794
|
+
return { result: JSON.stringify(a, null, 2) };
|
|
1795
|
+
}), s.set("get_cube_metadata", async () => {
|
|
1749
1796
|
const e = t.getMetadata();
|
|
1750
1797
|
return { result: JSON.stringify(e, null, 2) };
|
|
1751
|
-
}),
|
|
1798
|
+
}), s.set("execute_query", async (e) => {
|
|
1752
1799
|
try {
|
|
1753
|
-
let
|
|
1754
|
-
e.funnel ?
|
|
1800
|
+
let a;
|
|
1801
|
+
e.funnel ? a = { funnel: e.funnel } : e.flow ? a = { flow: e.flow } : e.retention ? a = { retention: e.retention } : a = {
|
|
1755
1802
|
measures: e.measures,
|
|
1756
1803
|
dimensions: e.dimensions,
|
|
1757
1804
|
filters: e.filters,
|
|
@@ -1759,7 +1806,7 @@ function ye(r) {
|
|
|
1759
1806
|
order: e.order,
|
|
1760
1807
|
limit: e.limit
|
|
1761
1808
|
};
|
|
1762
|
-
const n = await M(t, i, { query:
|
|
1809
|
+
const n = await M(t, i, { query: a });
|
|
1763
1810
|
return {
|
|
1764
1811
|
result: JSON.stringify({
|
|
1765
1812
|
rowCount: n.data.length,
|
|
@@ -1767,82 +1814,82 @@ function ye(r) {
|
|
|
1767
1814
|
annotation: n.annotation
|
|
1768
1815
|
}, null, 2)
|
|
1769
1816
|
};
|
|
1770
|
-
} catch (
|
|
1817
|
+
} catch (a) {
|
|
1771
1818
|
return {
|
|
1772
|
-
result: `Query execution failed: ${
|
|
1819
|
+
result: `Query execution failed: ${a instanceof Error ? a.message : "Unknown error"}`,
|
|
1773
1820
|
isError: !0
|
|
1774
1821
|
};
|
|
1775
1822
|
}
|
|
1776
|
-
}),
|
|
1823
|
+
}), s.set("add_portlet", async (e) => {
|
|
1777
1824
|
const n = {
|
|
1778
1825
|
number: "kpiNumber",
|
|
1779
1826
|
retention: "retentionHeatmap"
|
|
1780
1827
|
}[e.chartType] ?? e.chartType;
|
|
1781
|
-
let
|
|
1828
|
+
let l;
|
|
1782
1829
|
try {
|
|
1783
|
-
|
|
1830
|
+
l = JSON.parse(e.query);
|
|
1784
1831
|
} catch {
|
|
1785
1832
|
return {
|
|
1786
1833
|
result: "Invalid query: could not parse JSON string. Ensure `query` is a valid JSON string.",
|
|
1787
1834
|
isError: !0
|
|
1788
1835
|
};
|
|
1789
1836
|
}
|
|
1790
|
-
const
|
|
1791
|
-
if (!
|
|
1837
|
+
const u = t.validateQuery(l);
|
|
1838
|
+
if (!u.isValid)
|
|
1792
1839
|
return {
|
|
1793
1840
|
result: `Invalid query — fix these errors and retry:
|
|
1794
|
-
${
|
|
1841
|
+
${u.errors.join(`
|
|
1795
1842
|
`)}`,
|
|
1796
1843
|
isError: !0
|
|
1797
1844
|
};
|
|
1798
|
-
const
|
|
1799
|
-
let
|
|
1800
|
-
if (
|
|
1801
|
-
|
|
1845
|
+
const d = !!(l.funnel || l.flow || l.retention);
|
|
1846
|
+
let p;
|
|
1847
|
+
if (d)
|
|
1848
|
+
p = e.chartConfig ?? {};
|
|
1802
1849
|
else {
|
|
1803
|
-
const
|
|
1804
|
-
if (!
|
|
1850
|
+
const c = ue(n, e.chartConfig, l), g = pe(n, c, l);
|
|
1851
|
+
if (!g.isValid)
|
|
1805
1852
|
return {
|
|
1806
1853
|
result: `Chart config invalid — fix these errors and retry:
|
|
1807
|
-
${
|
|
1854
|
+
${g.errors.join(`
|
|
1808
1855
|
`)}`,
|
|
1809
1856
|
isError: !0
|
|
1810
1857
|
};
|
|
1811
|
-
|
|
1858
|
+
p = c;
|
|
1812
1859
|
}
|
|
1813
|
-
const
|
|
1814
|
-
id:
|
|
1860
|
+
const k = `portlet-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, f = {
|
|
1861
|
+
id: k,
|
|
1815
1862
|
title: e.title,
|
|
1816
1863
|
query: e.query,
|
|
1817
1864
|
chartType: n,
|
|
1818
|
-
chartConfig:
|
|
1865
|
+
chartConfig: p,
|
|
1819
1866
|
displayConfig: e.displayConfig
|
|
1820
1867
|
};
|
|
1821
1868
|
return {
|
|
1822
|
-
result: `Portlet "${e.title}" added to notebook (id: ${
|
|
1823
|
-
sideEffect: { type: "add_portlet", data:
|
|
1869
|
+
result: `Portlet "${e.title}" added to notebook (id: ${k}, chart: ${n}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
|
|
1870
|
+
sideEffect: { type: "add_portlet", data: f }
|
|
1824
1871
|
};
|
|
1825
|
-
}),
|
|
1826
|
-
const
|
|
1827
|
-
id:
|
|
1872
|
+
}), s.set("add_markdown", async (e) => {
|
|
1873
|
+
const a = `markdown-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, n = {
|
|
1874
|
+
id: a,
|
|
1828
1875
|
title: e.title,
|
|
1829
1876
|
content: e.content
|
|
1830
1877
|
};
|
|
1831
1878
|
return {
|
|
1832
|
-
result: `Markdown block added to notebook (id: ${
|
|
1879
|
+
result: `Markdown block added to notebook (id: ${a}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
|
|
1833
1880
|
sideEffect: { type: "add_markdown", data: n }
|
|
1834
1881
|
};
|
|
1835
|
-
}),
|
|
1882
|
+
}), s;
|
|
1836
1883
|
}
|
|
1837
|
-
async function*
|
|
1838
|
-
const { message: t, sessionId: i, semanticLayer:
|
|
1839
|
-
let
|
|
1884
|
+
async function* ge(o) {
|
|
1885
|
+
const { message: t, sessionId: i, semanticLayer: s, securityContext: e, agentConfig: a, apiKey: n } = o;
|
|
1886
|
+
let l;
|
|
1840
1887
|
try {
|
|
1841
|
-
const
|
|
1888
|
+
const m = await import(
|
|
1842
1889
|
/* webpackIgnore: true */
|
|
1843
1890
|
"@anthropic-ai/sdk"
|
|
1844
1891
|
);
|
|
1845
|
-
|
|
1892
|
+
l = m.default || m.Anthropic || m;
|
|
1846
1893
|
} catch {
|
|
1847
1894
|
yield {
|
|
1848
1895
|
type: "error",
|
|
@@ -1852,114 +1899,140 @@ async function* be(r) {
|
|
|
1852
1899
|
};
|
|
1853
1900
|
return;
|
|
1854
1901
|
}
|
|
1855
|
-
const
|
|
1902
|
+
const u = new l({ apiKey: n }), d = ce(), p = ye({ semanticLayer: s, securityContext: e }), k = s.getMetadata(), f = L(k), c = a.model || "claude-sonnet-4-6", g = a.maxTurns || 25, F = a.maxTokens || 4096, v = [
|
|
1856
1903
|
{ role: "user", content: t }
|
|
1857
1904
|
];
|
|
1858
1905
|
try {
|
|
1859
|
-
for (let
|
|
1860
|
-
const
|
|
1861
|
-
model:
|
|
1862
|
-
max_tokens:
|
|
1863
|
-
system:
|
|
1864
|
-
tools:
|
|
1865
|
-
messages:
|
|
1906
|
+
for (let m = 0; m < g; m++) {
|
|
1907
|
+
const C = await u.messages.create({
|
|
1908
|
+
model: c,
|
|
1909
|
+
max_tokens: F,
|
|
1910
|
+
system: f,
|
|
1911
|
+
tools: d,
|
|
1912
|
+
messages: v,
|
|
1866
1913
|
stream: !0
|
|
1867
|
-
}),
|
|
1868
|
-
let
|
|
1869
|
-
for await (const h of
|
|
1914
|
+
}), y = [];
|
|
1915
|
+
let x = -1, w = "", V = "";
|
|
1916
|
+
for await (const h of C)
|
|
1870
1917
|
switch (h.type) {
|
|
1871
1918
|
case "content_block_start": {
|
|
1872
|
-
|
|
1873
|
-
const
|
|
1874
|
-
|
|
1919
|
+
x++;
|
|
1920
|
+
const r = h.content_block;
|
|
1921
|
+
r.type === "tool_use" ? (y.push({ type: "tool_use", id: r.id, name: r.name, input: {} }), w = "", yield {
|
|
1875
1922
|
type: "tool_use_start",
|
|
1876
|
-
data: { id:
|
|
1877
|
-
}) :
|
|
1923
|
+
data: { id: r.id, name: r.name, input: void 0 }
|
|
1924
|
+
}) : r.type === "text" && y.push({ type: "text", text: "" });
|
|
1878
1925
|
break;
|
|
1879
1926
|
}
|
|
1880
1927
|
case "content_block_delta": {
|
|
1881
|
-
const
|
|
1882
|
-
if (
|
|
1883
|
-
const A =
|
|
1884
|
-
A && (A.text = (A.text || "") +
|
|
1885
|
-
} else
|
|
1928
|
+
const r = h.delta;
|
|
1929
|
+
if (r.type === "text_delta" && r.text) {
|
|
1930
|
+
const A = y[x];
|
|
1931
|
+
A && (A.text = (A.text || "") + r.text), yield { type: "text_delta", data: r.text };
|
|
1932
|
+
} else r.type === "input_json_delta" && r.partial_json && (w += r.partial_json);
|
|
1886
1933
|
break;
|
|
1887
1934
|
}
|
|
1888
1935
|
case "content_block_stop": {
|
|
1889
|
-
const
|
|
1890
|
-
if (
|
|
1936
|
+
const r = y[x];
|
|
1937
|
+
if (r?.type === "tool_use" && w) {
|
|
1891
1938
|
try {
|
|
1892
|
-
|
|
1939
|
+
r.input = JSON.parse(w);
|
|
1893
1940
|
} catch {
|
|
1894
|
-
|
|
1941
|
+
r.input = {};
|
|
1895
1942
|
}
|
|
1896
|
-
|
|
1943
|
+
w = "";
|
|
1897
1944
|
}
|
|
1898
1945
|
break;
|
|
1899
1946
|
}
|
|
1900
1947
|
case "message_delta": {
|
|
1901
|
-
const
|
|
1902
|
-
|
|
1948
|
+
const r = h.delta;
|
|
1949
|
+
r.stop_reason && (V = r.stop_reason);
|
|
1903
1950
|
break;
|
|
1904
1951
|
}
|
|
1905
1952
|
}
|
|
1906
|
-
if (
|
|
1953
|
+
if (v.push({ role: "assistant", content: y }), V !== "tool_use")
|
|
1907
1954
|
break;
|
|
1908
|
-
const
|
|
1909
|
-
for (const h of
|
|
1955
|
+
const D = [];
|
|
1956
|
+
for (const h of y) {
|
|
1910
1957
|
if (h.type !== "tool_use") continue;
|
|
1911
|
-
const
|
|
1912
|
-
if (!
|
|
1913
|
-
|
|
1958
|
+
const r = h.name, A = h.input || {}, T = h.id, E = p.get(r);
|
|
1959
|
+
if (!E) {
|
|
1960
|
+
D.push({
|
|
1914
1961
|
type: "tool_result",
|
|
1915
|
-
tool_use_id:
|
|
1916
|
-
content: `Unknown tool: ${
|
|
1962
|
+
tool_use_id: T,
|
|
1963
|
+
content: `Unknown tool: ${r}`,
|
|
1917
1964
|
is_error: !0
|
|
1918
1965
|
}), yield {
|
|
1919
1966
|
type: "tool_use_result",
|
|
1920
|
-
data: { id:
|
|
1967
|
+
data: { id: T, name: r, result: `Unknown tool: ${r}`, isError: !0 }
|
|
1921
1968
|
};
|
|
1922
1969
|
continue;
|
|
1923
1970
|
}
|
|
1924
1971
|
try {
|
|
1925
|
-
const b = await
|
|
1926
|
-
b.sideEffect && (yield b.sideEffect),
|
|
1972
|
+
const b = await E(A);
|
|
1973
|
+
b.sideEffect && (yield b.sideEffect), D.push({
|
|
1927
1974
|
type: "tool_result",
|
|
1928
|
-
tool_use_id:
|
|
1975
|
+
tool_use_id: T,
|
|
1929
1976
|
content: b.result,
|
|
1930
1977
|
...b.isError ? { is_error: !0 } : {}
|
|
1931
1978
|
}), yield {
|
|
1932
1979
|
type: "tool_use_result",
|
|
1933
|
-
data: { id:
|
|
1980
|
+
data: { id: T, name: r, result: b.result, ...b.isError ? { isError: !0 } : {} }
|
|
1934
1981
|
};
|
|
1935
1982
|
} catch (b) {
|
|
1936
|
-
const
|
|
1937
|
-
|
|
1983
|
+
const I = b instanceof Error ? b.message : "Tool execution failed";
|
|
1984
|
+
D.push({
|
|
1938
1985
|
type: "tool_result",
|
|
1939
|
-
tool_use_id:
|
|
1940
|
-
content:
|
|
1986
|
+
tool_use_id: T,
|
|
1987
|
+
content: I,
|
|
1941
1988
|
is_error: !0
|
|
1942
1989
|
}), yield {
|
|
1943
1990
|
type: "tool_use_result",
|
|
1944
|
-
data: { id:
|
|
1991
|
+
data: { id: T, name: r, result: I, isError: !0 }
|
|
1945
1992
|
};
|
|
1946
1993
|
}
|
|
1947
1994
|
}
|
|
1948
|
-
yield { type: "turn_complete", data: {} },
|
|
1995
|
+
yield { type: "turn_complete", data: {} }, v.push({ role: "user", content: D });
|
|
1949
1996
|
}
|
|
1950
1997
|
yield {
|
|
1951
1998
|
type: "done",
|
|
1952
1999
|
data: { sessionId: i || "" }
|
|
1953
2000
|
};
|
|
1954
|
-
} catch (
|
|
2001
|
+
} catch (m) {
|
|
1955
2002
|
yield {
|
|
1956
2003
|
type: "error",
|
|
1957
2004
|
data: {
|
|
1958
|
-
message:
|
|
2005
|
+
message: fe(m)
|
|
1959
2006
|
}
|
|
1960
2007
|
};
|
|
1961
2008
|
}
|
|
1962
2009
|
}
|
|
2010
|
+
function fe(o) {
|
|
2011
|
+
if (!o || !(o instanceof Error))
|
|
2012
|
+
return "Something went wrong. Please try again.";
|
|
2013
|
+
const t = o.message || "", i = {
|
|
2014
|
+
overloaded_error: "The AI service is temporarily overloaded. Please try again in a moment.",
|
|
2015
|
+
rate_limit_error: "Too many requests. Please wait a moment and try again.",
|
|
2016
|
+
api_error: "The AI service encountered an error. Please try again.",
|
|
2017
|
+
authentication_error: "Authentication failed. Please check your API key configuration.",
|
|
2018
|
+
invalid_request_error: "There was a problem with the request. Please try again."
|
|
2019
|
+
}, s = o;
|
|
2020
|
+
if (s.status || s.type) {
|
|
2021
|
+
const e = s.error?.type || s.type || "";
|
|
2022
|
+
if (i[e])
|
|
2023
|
+
return i[e];
|
|
2024
|
+
}
|
|
2025
|
+
if (t.startsWith("{") || t.startsWith("Error: {")) {
|
|
2026
|
+
try {
|
|
2027
|
+
const e = JSON.parse(t.replace(/^Error:\s*/, "")), a = e.error?.type || e.type || "";
|
|
2028
|
+
if (i[a])
|
|
2029
|
+
return i[a];
|
|
2030
|
+
} catch {
|
|
2031
|
+
}
|
|
2032
|
+
return "The AI service encountered an error. Please try again.";
|
|
2033
|
+
}
|
|
2034
|
+
return t;
|
|
2035
|
+
}
|
|
1963
2036
|
export {
|
|
1964
|
-
|
|
2037
|
+
ge as handleAgentChat
|
|
1965
2038
|
};
|