drizzle-cube 0.4.4 → 0.4.7
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 +8 -4
- package/dist/adapters/express/index.d.ts +7 -0
- package/dist/adapters/express/index.js +189 -139
- package/dist/adapters/fastify/index.cjs +8 -4
- package/dist/adapters/fastify/index.d.ts +7 -0
- package/dist/adapters/fastify/index.js +209 -150
- package/dist/adapters/handler-D6l8AbJV.cjs +7 -0
- package/dist/adapters/handler-DsNgnIPK.js +458 -0
- package/dist/adapters/hono/index.cjs +8 -4
- package/dist/adapters/hono/index.d.ts +7 -0
- package/dist/adapters/hono/index.js +202 -144
- package/dist/adapters/{mcp-transport-BqLo4hKi.cjs → mcp-transport-BB998cy5.cjs} +21 -21
- package/dist/adapters/{mcp-transport-YHDZWKOi.js → mcp-transport-DFTCWene.js} +4 -0
- package/dist/adapters/nextjs/index.cjs +7 -3
- package/dist/adapters/nextjs/index.d.ts +14 -0
- package/dist/adapters/nextjs/index.js +220 -144
- package/dist/client/charts.js +13 -13
- package/dist/client/chunks/{RetentionCombinedChart-BK8N-MOQ.js → RetentionCombinedChart-CEI8KQ3t.js} +2 -2
- package/dist/client/chunks/{RetentionCombinedChart-BK8N-MOQ.js.map → RetentionCombinedChart-CEI8KQ3t.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-CNBmAGAO.js → analysis-builder-Dn8xpgPQ.js} +6 -6
- package/dist/client/chunks/{analysis-builder-CNBmAGAO.js.map → analysis-builder-Dn8xpgPQ.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-shared-INGGwyTG.js → analysis-builder-shared-D3xYzXlh.js} +2 -2
- package/dist/client/chunks/{analysis-builder-shared-INGGwyTG.js.map → analysis-builder-shared-D3xYzXlh.js.map} +1 -1
- package/dist/client/chunks/{chart-activity-grid-DvgTYQaE.js → chart-activity-grid-DStNr34n.js} +2 -2
- package/dist/client/chunks/{chart-activity-grid-DvgTYQaE.js.map → chart-activity-grid-DStNr34n.js.map} +1 -1
- package/dist/client/chunks/{chart-area-BKjd_STS.js → chart-area-QKKboTbq.js} +3 -3
- package/dist/client/chunks/{chart-area-BKjd_STS.js.map → chart-area-QKKboTbq.js.map} +1 -1
- package/dist/client/chunks/{chart-bar-DBI41w05.js → chart-bar-HpXF42H1.js} +2 -2
- package/dist/client/chunks/{chart-bar-DBI41w05.js.map → chart-bar-HpXF42H1.js.map} +1 -1
- package/dist/client/chunks/{chart-bubble-BD-1kneU.js → chart-bubble-Bf42A1-B.js} +2 -2
- package/dist/client/chunks/{chart-bubble-BD-1kneU.js.map → chart-bubble-Bf42A1-B.js.map} +1 -1
- package/dist/client/chunks/{chart-config-markdown-6fsr-U6_.js → chart-config-markdown-BXKL5TbQ.js} +8 -1
- package/dist/client/chunks/{chart-config-markdown-6fsr-U6_.js.map → chart-config-markdown-BXKL5TbQ.js.map} +1 -1
- package/dist/client/chunks/{chart-data-table-B74HLpAx.js → chart-data-table-Ch_1c1Zo.js} +2 -2
- package/dist/client/chunks/{chart-data-table-B74HLpAx.js.map → chart-data-table-Ch_1c1Zo.js.map} +1 -1
- package/dist/client/chunks/{chart-funnel-DQ9cW6j9.js → chart-funnel-C9kenCpp.js} +2 -2
- package/dist/client/chunks/{chart-funnel-DQ9cW6j9.js.map → chart-funnel-C9kenCpp.js.map} +1 -1
- package/dist/client/chunks/{chart-heat-map-CpIr4tbs.js → chart-heat-map-CYGemyPB.js} +2 -2
- package/dist/client/chunks/{chart-heat-map-CpIr4tbs.js.map → chart-heat-map-CYGemyPB.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-delta-DPcSazD3.js → chart-kpi-delta-CWCmi8vL.js} +3 -3
- package/dist/client/chunks/{chart-kpi-delta-DPcSazD3.js.map → chart-kpi-delta-CWCmi8vL.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-number-D62PzKZ1.js → chart-kpi-number-C-5m3qt5.js} +2 -2
- package/dist/client/chunks/{chart-kpi-number-D62PzKZ1.js.map → chart-kpi-number-C-5m3qt5.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-text-B6Z5tFV1.js → chart-kpi-text--t4ibPmx.js} +3 -3
- package/dist/client/chunks/{chart-kpi-text-B6Z5tFV1.js.map → chart-kpi-text--t4ibPmx.js.map} +1 -1
- package/dist/client/chunks/{chart-line-Ds4BYA0K.js → chart-line-C7YcMWBw.js} +3 -3
- package/dist/client/chunks/{chart-line-Ds4BYA0K.js.map → chart-line-C7YcMWBw.js.map} +1 -1
- package/dist/client/chunks/chart-markdown-Du4Z2iqK.js +2695 -0
- package/dist/client/chunks/chart-markdown-Du4Z2iqK.js.map +1 -0
- package/dist/client/chunks/{chart-pie-BBrLh0iU.js → chart-pie-C4SuxKSN.js} +2 -2
- package/dist/client/chunks/{chart-pie-BBrLh0iU.js.map → chart-pie-C4SuxKSN.js.map} +1 -1
- package/dist/client/chunks/{chart-radar-vr5FgjHT.js → chart-radar-BW3Z_-Ly.js} +2 -2
- package/dist/client/chunks/{chart-radar-vr5FgjHT.js.map → chart-radar-BW3Z_-Ly.js.map} +1 -1
- package/dist/client/chunks/{chart-radial-bar-BV_3Nm5P.js → chart-radial-bar-0Fa3aeP5.js} +2 -2
- package/dist/client/chunks/{chart-radial-bar-BV_3Nm5P.js.map → chart-radial-bar-0Fa3aeP5.js.map} +1 -1
- package/dist/client/chunks/{chart-sankey-CHROzr4S.js → chart-sankey-DBghfbg1.js} +2 -2
- package/dist/client/chunks/{chart-sankey-CHROzr4S.js.map → chart-sankey-DBghfbg1.js.map} +1 -1
- package/dist/client/chunks/{chart-scatter-DbRTU3FG.js → chart-scatter-DOVu1TNq.js} +2 -2
- package/dist/client/chunks/{chart-scatter-DbRTU3FG.js.map → chart-scatter-DOVu1TNq.js.map} +1 -1
- package/dist/client/chunks/{chart-sunburst-B-aPUzYL.js → chart-sunburst-LfNthFlZ.js} +2 -2
- package/dist/client/chunks/{chart-sunburst-B-aPUzYL.js.map → chart-sunburst-LfNthFlZ.js.map} +1 -1
- package/dist/client/chunks/{chart-tree-map-qY148fiC.js → chart-tree-map-DZtQPyWX.js} +2 -2
- package/dist/client/chunks/{chart-tree-map-qY148fiC.js.map → chart-tree-map-DZtQPyWX.js.map} +1 -1
- package/dist/client/chunks/{chartConfigRegistry-Di34paQH.js → chartConfigRegistry-C5dZm-ZK.js} +2 -2
- package/dist/client/chunks/{chartConfigRegistry-Di34paQH.js.map → chartConfigRegistry-C5dZm-ZK.js.map} +1 -1
- package/dist/client/chunks/{charts-core-T8UglYyq.js → charts-core-DmGfleFz.js} +199 -187
- package/dist/client/chunks/{charts-core-T8UglYyq.js.map → charts-core-DmGfleFz.js.map} +1 -1
- package/dist/client/chunks/{charts-loader-YnhJHubD.js → charts-loader-DcFWOUeV.js} +21 -21
- package/dist/client/chunks/{charts-loader-YnhJHubD.js.map → charts-loader-DcFWOUeV.js.map} +1 -1
- package/dist/client/chunks/{components-D0i1yQsk.js → components-Bdt1AmzS.js} +3521 -3369
- package/dist/client/chunks/components-Bdt1AmzS.js.map +1 -0
- package/dist/client/components/AgenticNotebook/AgentChatPanel.d.ts +8 -0
- package/dist/client/components/AgenticNotebook/ChatInput.d.ts +14 -0
- package/dist/client/components/AgenticNotebook/ChatMessage.d.ts +7 -0
- package/dist/client/components/AgenticNotebook/NotebookCanvas.d.ts +3 -0
- package/dist/client/components/AgenticNotebook/NotebookMarkdownBlock.d.ts +12 -0
- package/dist/client/components/AgenticNotebook/NotebookPortletBlock.d.ts +12 -0
- package/dist/client/components/AgenticNotebook/index.d.ts +34 -0
- package/dist/client/components/DashboardPortletCard.d.ts +3 -2
- package/dist/client/components.js +1 -1
- package/dist/client/hooks/dashboard/layoutUtils.d.ts +7 -0
- package/dist/client/hooks/dashboard/useDashboardController.d.ts +53 -0
- package/dist/client/hooks/dashboard/useGridLayoutEngine.d.ts +10 -0
- package/dist/client/hooks/dashboard/useRowLayoutEngine.d.ts +18 -0
- package/dist/client/hooks/useAgentChat.d.ts +36 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +923 -187
- package/dist/client/index.js.map +1 -1
- package/dist/client/stores/notebookStore.d.ts +152 -0
- package/dist/client/styles.css +1 -1
- package/dist/client/utils.js +4 -4
- package/dist/client-bundle-stats.html +1 -1
- package/dist/server/index.cjs +101 -91
- package/dist/server/index.d.ts +155 -0
- package/dist/server/index.js +4423 -3609
- package/package.json +7 -1
- package/dist/client/chunks/chart-markdown-Rq6ORisB.js +0 -276
- package/dist/client/chunks/chart-markdown-Rq6ORisB.js.map +0 -1
- package/dist/client/chunks/components-D0i1yQsk.js.map +0 -1
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import { h as I, Q as N, j, D as M } from "./mcp-transport-DFTCWene.js";
|
|
2
|
+
import { handleDiscover as z, handleLoad as D } from "./utils.js";
|
|
3
|
+
function O(r) {
|
|
4
|
+
if (r.length === 0)
|
|
5
|
+
return "No cubes are currently available.";
|
|
6
|
+
const o = ["## Available Cubes", ""];
|
|
7
|
+
for (const a of r) {
|
|
8
|
+
if (o.push(`### ${a.name}`), a.description && o.push(a.description), a.measures && a.measures.length > 0) {
|
|
9
|
+
o.push(""), o.push("**Measures:**");
|
|
10
|
+
for (const s of a.measures) {
|
|
11
|
+
const e = s.description ? ` - ${s.description}` : "";
|
|
12
|
+
o.push(`- \`${a.name}.${s.name}\` (${s.type})${e}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (a.dimensions && a.dimensions.length > 0) {
|
|
16
|
+
o.push(""), o.push("**Dimensions:**");
|
|
17
|
+
for (const s of a.dimensions) {
|
|
18
|
+
const e = s.description ? ` - ${s.description}` : "";
|
|
19
|
+
o.push(`- \`${a.name}.${s.name}\` (${s.type})${e}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (a.relationships && a.relationships.length > 0) {
|
|
23
|
+
o.push(""), o.push("**Joins:**");
|
|
24
|
+
for (const s of a.relationships)
|
|
25
|
+
o.push(`- → \`${s.targetCube}\` (${s.relationship})`);
|
|
26
|
+
}
|
|
27
|
+
o.push("");
|
|
28
|
+
}
|
|
29
|
+
return o.join(`
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
function f(r) {
|
|
33
|
+
return r.messages.map((o) => o.content.text).join(`
|
|
34
|
+
|
|
35
|
+
`);
|
|
36
|
+
}
|
|
37
|
+
function U(r) {
|
|
38
|
+
return [
|
|
39
|
+
"# Drizzle Cube Analytics Agent",
|
|
40
|
+
"",
|
|
41
|
+
"You are an analytics agent that helps users explore and visualize data.",
|
|
42
|
+
"You have access to a semantic layer with cubes (data models) that you can query.",
|
|
43
|
+
"",
|
|
44
|
+
"## Your Workflow",
|
|
45
|
+
"",
|
|
46
|
+
"1. **Discover** available cubes using `discover_cubes` to understand the data",
|
|
47
|
+
"2. **Explain your approach** by calling `add_markdown` to describe what you plan to analyze and why",
|
|
48
|
+
"3. **Query** data using `execute_query` with properly structured queries",
|
|
49
|
+
"4. **Explain results** by calling `add_markdown` to describe what the data shows, key insights, and methodology",
|
|
50
|
+
"5. **Visualize** results by calling `add_portlet` to add charts/tables to the notebook",
|
|
51
|
+
"",
|
|
52
|
+
"## Important Guidelines",
|
|
53
|
+
"",
|
|
54
|
+
"- ALWAYS discover cubes first before attempting queries",
|
|
55
|
+
"- Use `add_portlet` to create visualizations after getting query results",
|
|
56
|
+
"- Use `add_markdown` to explain your findings, methodology, and insights",
|
|
57
|
+
"- Choose appropriate chart types: bar for categories, line for trends, table for detailed data",
|
|
58
|
+
"- When showing data, always add both a portlet (visualization) and markdown (explanation)",
|
|
59
|
+
"- If a query fails, explain the error and try an alternative approach",
|
|
60
|
+
"",
|
|
61
|
+
"## Output Format Rules",
|
|
62
|
+
"",
|
|
63
|
+
"### CRITICAL: Always think before acting",
|
|
64
|
+
"- 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
|
+
"- This applies to EVERY turn, including turns where you are adding visualizations or explanations to the notebook.",
|
|
66
|
+
`- Even when adding multiple portlets/markdowns in sequence, each turn must start with text like "Now I'll add the productivity chart." or "Next, let me visualize the department breakdown."`,
|
|
67
|
+
'- Example good turn: "Let me discover what data is available." → discover_cubes',
|
|
68
|
+
`- Example good turn: "I'll add a bar chart showing the top employees." → add_markdown → add_portlet`,
|
|
69
|
+
"- Example bad turn: (no text) → add_portlet ← NEVER do this",
|
|
70
|
+
"",
|
|
71
|
+
"### Text vs Notebook",
|
|
72
|
+
"- ALL analysis, findings, methodology, and insights MUST go through `add_markdown` tool calls — never in your text responses",
|
|
73
|
+
"- Your text responses must be 1-2 short sentences (under 50 words) summarizing what you are about to do next — status updates only",
|
|
74
|
+
"- Never use markdown formatting (headers, bullets, bold, code blocks) in text responses — plain sentences only",
|
|
75
|
+
"",
|
|
76
|
+
"### Notebook content rules",
|
|
77
|
+
"- Before each `add_portlet`, ALWAYS call `add_markdown` first to explain WHY you are adding this visualization and what it shows",
|
|
78
|
+
"- Before calling `add_portlet`, verify the query is valid: all fields in `order` must also appear in `measures` or `dimensions`",
|
|
79
|
+
'- Never put data tables in markdown blocks — use `add_portlet` with chartType "table" instead',
|
|
80
|
+
"- Think out loud in the notebook: use `add_markdown` to share your reasoning at each step so users can follow along",
|
|
81
|
+
"",
|
|
82
|
+
"---",
|
|
83
|
+
"",
|
|
84
|
+
f(I),
|
|
85
|
+
"",
|
|
86
|
+
"---",
|
|
87
|
+
"",
|
|
88
|
+
f(N),
|
|
89
|
+
"",
|
|
90
|
+
"---",
|
|
91
|
+
"",
|
|
92
|
+
f(j),
|
|
93
|
+
"",
|
|
94
|
+
"---",
|
|
95
|
+
"",
|
|
96
|
+
f(M),
|
|
97
|
+
"",
|
|
98
|
+
"---",
|
|
99
|
+
"",
|
|
100
|
+
O(r)
|
|
101
|
+
].join(`
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
function L() {
|
|
105
|
+
return [
|
|
106
|
+
// Tool 1: discover_cubes
|
|
107
|
+
{
|
|
108
|
+
name: "discover_cubes",
|
|
109
|
+
description: "Search for available data cubes by topic or intent. Call this FIRST to understand what data is available. Returns cube names, measures, dimensions, and relationships.",
|
|
110
|
+
input_schema: {
|
|
111
|
+
type: "object",
|
|
112
|
+
properties: {
|
|
113
|
+
topic: { type: "string", description: 'Keyword to search (e.g., "sales", "employees")' },
|
|
114
|
+
intent: { type: "string", description: 'Natural language goal (e.g., "analyze productivity trends")' },
|
|
115
|
+
limit: { type: "number", description: "Max results (default: 10)" },
|
|
116
|
+
minScore: { type: "number", description: "Min relevance 0-1 (default: 0.1)" }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
// Tool 2: get_cube_metadata
|
|
121
|
+
{
|
|
122
|
+
name: "get_cube_metadata",
|
|
123
|
+
description: "Get full metadata for all registered cubes including all measures, dimensions, types, and relationships. Use this for detailed schema information.",
|
|
124
|
+
input_schema: {
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: {}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
// Tool 3: execute_query
|
|
130
|
+
{
|
|
131
|
+
name: "execute_query",
|
|
132
|
+
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.",
|
|
133
|
+
input_schema: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {
|
|
136
|
+
measures: {
|
|
137
|
+
type: "array",
|
|
138
|
+
items: { type: "string" },
|
|
139
|
+
description: 'Aggregation measures (e.g., ["Employees.count"])'
|
|
140
|
+
},
|
|
141
|
+
dimensions: {
|
|
142
|
+
type: "array",
|
|
143
|
+
items: { type: "string" },
|
|
144
|
+
description: 'Grouping dimensions (e.g., ["Employees.name"])'
|
|
145
|
+
},
|
|
146
|
+
filters: {
|
|
147
|
+
type: "array",
|
|
148
|
+
items: {
|
|
149
|
+
type: "object",
|
|
150
|
+
properties: {
|
|
151
|
+
member: { type: "string" },
|
|
152
|
+
operator: { type: "string" },
|
|
153
|
+
values: { type: "array", items: {} }
|
|
154
|
+
},
|
|
155
|
+
required: ["member", "operator"]
|
|
156
|
+
},
|
|
157
|
+
description: "Filter conditions"
|
|
158
|
+
},
|
|
159
|
+
timeDimensions: {
|
|
160
|
+
type: "array",
|
|
161
|
+
items: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
dimension: { type: "string" },
|
|
165
|
+
granularity: { type: "string" },
|
|
166
|
+
dateRange: {}
|
|
167
|
+
},
|
|
168
|
+
required: ["dimension"]
|
|
169
|
+
},
|
|
170
|
+
description: "Time dimensions with optional granularity"
|
|
171
|
+
},
|
|
172
|
+
order: {
|
|
173
|
+
type: "object",
|
|
174
|
+
description: 'Sort order (e.g., {"Employees.count": "desc"})'
|
|
175
|
+
},
|
|
176
|
+
limit: {
|
|
177
|
+
type: "number",
|
|
178
|
+
description: "Row limit"
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
// Tool 4: add_portlet
|
|
184
|
+
{
|
|
185
|
+
name: "add_portlet",
|
|
186
|
+
description: "Add a chart or table visualization to the notebook. The query is validated before adding — if invalid, an error is returned so you can fix the query. The portlet fetches its own data - you do NOT need to pass data to it.",
|
|
187
|
+
input_schema: {
|
|
188
|
+
type: "object",
|
|
189
|
+
properties: {
|
|
190
|
+
title: { type: "string", description: "Title for the visualization" },
|
|
191
|
+
query: { type: "string", description: "JSON string of the CubeQuery to visualize" },
|
|
192
|
+
chartType: {
|
|
193
|
+
type: "string",
|
|
194
|
+
enum: [
|
|
195
|
+
"bar",
|
|
196
|
+
"line",
|
|
197
|
+
"area",
|
|
198
|
+
"pie",
|
|
199
|
+
"scatter",
|
|
200
|
+
"radar",
|
|
201
|
+
"bubble",
|
|
202
|
+
"table",
|
|
203
|
+
"number",
|
|
204
|
+
"funnel",
|
|
205
|
+
"heatmap",
|
|
206
|
+
"sankey",
|
|
207
|
+
"retention"
|
|
208
|
+
],
|
|
209
|
+
description: "Chart type to render"
|
|
210
|
+
},
|
|
211
|
+
chartConfig: {
|
|
212
|
+
type: "object",
|
|
213
|
+
properties: {
|
|
214
|
+
xAxis: { type: "array", items: { type: "string" } },
|
|
215
|
+
yAxis: { type: "array", items: { type: "string" } },
|
|
216
|
+
series: { type: "array", items: { type: "string" } },
|
|
217
|
+
sizeField: { type: "string" },
|
|
218
|
+
colorField: { type: "string" }
|
|
219
|
+
},
|
|
220
|
+
description: "Chart axis configuration"
|
|
221
|
+
},
|
|
222
|
+
displayConfig: {
|
|
223
|
+
type: "object",
|
|
224
|
+
properties: {
|
|
225
|
+
showLegend: { type: "boolean" },
|
|
226
|
+
showGrid: { type: "boolean" },
|
|
227
|
+
showTooltip: { type: "boolean" },
|
|
228
|
+
stacked: { type: "boolean" },
|
|
229
|
+
orientation: { type: "string", enum: ["horizontal", "vertical"] }
|
|
230
|
+
},
|
|
231
|
+
description: "Chart display configuration"
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
required: ["title", "query", "chartType"]
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
// Tool 5: add_markdown
|
|
238
|
+
{
|
|
239
|
+
name: "add_markdown",
|
|
240
|
+
description: "Add an explanation or analysis text block to the notebook. Use markdown formatting. Use this to explain findings, methodology, and insights alongside visualizations.",
|
|
241
|
+
input_schema: {
|
|
242
|
+
type: "object",
|
|
243
|
+
properties: {
|
|
244
|
+
title: { type: "string", description: "Optional title for the text block" },
|
|
245
|
+
content: { type: "string", description: "Markdown content to display" }
|
|
246
|
+
},
|
|
247
|
+
required: ["content"]
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
];
|
|
251
|
+
}
|
|
252
|
+
function P(r) {
|
|
253
|
+
const { semanticLayer: o, securityContext: a } = r, s = /* @__PURE__ */ new Map();
|
|
254
|
+
return s.set("discover_cubes", async (e) => {
|
|
255
|
+
const n = await z(o, {
|
|
256
|
+
topic: e.topic,
|
|
257
|
+
intent: e.intent,
|
|
258
|
+
limit: e.limit,
|
|
259
|
+
minScore: e.minScore
|
|
260
|
+
});
|
|
261
|
+
return { result: JSON.stringify(n, null, 2) };
|
|
262
|
+
}), s.set("get_cube_metadata", async () => {
|
|
263
|
+
const e = o.getMetadata();
|
|
264
|
+
return { result: JSON.stringify(e, null, 2) };
|
|
265
|
+
}), s.set("execute_query", async (e) => {
|
|
266
|
+
try {
|
|
267
|
+
const n = {
|
|
268
|
+
measures: e.measures,
|
|
269
|
+
dimensions: e.dimensions,
|
|
270
|
+
filters: e.filters,
|
|
271
|
+
timeDimensions: e.timeDimensions,
|
|
272
|
+
order: e.order,
|
|
273
|
+
limit: e.limit
|
|
274
|
+
}, i = await D(o, a, { query: n });
|
|
275
|
+
return {
|
|
276
|
+
result: JSON.stringify({
|
|
277
|
+
rowCount: i.data.length,
|
|
278
|
+
data: i.data,
|
|
279
|
+
annotation: i.annotation
|
|
280
|
+
}, null, 2)
|
|
281
|
+
};
|
|
282
|
+
} catch (n) {
|
|
283
|
+
return {
|
|
284
|
+
result: `Query execution failed: ${n instanceof Error ? n.message : "Unknown error"}`,
|
|
285
|
+
isError: !0
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}), s.set("add_portlet", async (e) => {
|
|
289
|
+
let n;
|
|
290
|
+
try {
|
|
291
|
+
n = JSON.parse(e.query);
|
|
292
|
+
} catch {
|
|
293
|
+
return {
|
|
294
|
+
result: "Invalid query: could not parse JSON string. Ensure `query` is a valid JSON string.",
|
|
295
|
+
isError: !0
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
const i = o.validateQuery(n);
|
|
299
|
+
if (!i.isValid)
|
|
300
|
+
return {
|
|
301
|
+
result: `Invalid query — fix these errors and retry:
|
|
302
|
+
${i.errors.join(`
|
|
303
|
+
`)}`,
|
|
304
|
+
isError: !0
|
|
305
|
+
};
|
|
306
|
+
const y = `portlet-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, b = {
|
|
307
|
+
id: y,
|
|
308
|
+
title: e.title,
|
|
309
|
+
query: e.query,
|
|
310
|
+
chartType: e.chartType,
|
|
311
|
+
chartConfig: e.chartConfig,
|
|
312
|
+
displayConfig: e.displayConfig
|
|
313
|
+
};
|
|
314
|
+
return {
|
|
315
|
+
result: `Portlet "${e.title}" added to notebook (id: ${y}, chart: ${e.chartType}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
|
|
316
|
+
sideEffect: { type: "add_portlet", data: b }
|
|
317
|
+
};
|
|
318
|
+
}), s.set("add_markdown", async (e) => {
|
|
319
|
+
const n = `markdown-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`, i = {
|
|
320
|
+
id: n,
|
|
321
|
+
title: e.title,
|
|
322
|
+
content: e.content
|
|
323
|
+
};
|
|
324
|
+
return {
|
|
325
|
+
result: `Markdown block added to notebook (id: ${n}). [Reminder: in your next response, start with a brief sentence about what you will do next BEFORE making any tool calls.]`,
|
|
326
|
+
sideEffect: { type: "add_markdown", data: i }
|
|
327
|
+
};
|
|
328
|
+
}), s;
|
|
329
|
+
}
|
|
330
|
+
async function* J(r) {
|
|
331
|
+
const { message: o, sessionId: a, semanticLayer: s, securityContext: e, agentConfig: n, apiKey: i } = r;
|
|
332
|
+
let y;
|
|
333
|
+
try {
|
|
334
|
+
const l = await import(
|
|
335
|
+
/* webpackIgnore: true */
|
|
336
|
+
"@anthropic-ai/sdk"
|
|
337
|
+
);
|
|
338
|
+
y = l.default || l.Anthropic || l;
|
|
339
|
+
} catch {
|
|
340
|
+
yield {
|
|
341
|
+
type: "error",
|
|
342
|
+
data: {
|
|
343
|
+
message: "@anthropic-ai/sdk is required. Install it with: npm install @anthropic-ai/sdk"
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const b = new y({ apiKey: i }), E = L(), T = P({ semanticLayer: s, securityContext: e }), q = s.getMetadata(), C = U(q), R = n.model || "claude-sonnet-4-6", $ = n.maxTurns || 25, S = n.maxTokens || 4096, _ = [
|
|
349
|
+
{ role: "user", content: o }
|
|
350
|
+
];
|
|
351
|
+
try {
|
|
352
|
+
for (let l = 0; l < $; l++) {
|
|
353
|
+
const A = await b.messages.create({
|
|
354
|
+
model: R,
|
|
355
|
+
max_tokens: S,
|
|
356
|
+
system: C,
|
|
357
|
+
tools: E,
|
|
358
|
+
messages: _,
|
|
359
|
+
stream: !0
|
|
360
|
+
}), u = [];
|
|
361
|
+
let w = -1, m = "", x = "";
|
|
362
|
+
for await (const d of A)
|
|
363
|
+
switch (d.type) {
|
|
364
|
+
case "content_block_start": {
|
|
365
|
+
w++;
|
|
366
|
+
const t = d.content_block;
|
|
367
|
+
t.type === "tool_use" ? (u.push({ type: "tool_use", id: t.id, name: t.name, input: {} }), m = "", yield {
|
|
368
|
+
type: "tool_use_start",
|
|
369
|
+
data: { id: t.id, name: t.name, input: void 0 }
|
|
370
|
+
}) : t.type === "text" && u.push({ type: "text", text: "" });
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
case "content_block_delta": {
|
|
374
|
+
const t = d.delta;
|
|
375
|
+
if (t.type === "text_delta" && t.text) {
|
|
376
|
+
const h = u[w];
|
|
377
|
+
h && (h.text = (h.text || "") + t.text), yield { type: "text_delta", data: t.text };
|
|
378
|
+
} else t.type === "input_json_delta" && t.partial_json && (m += t.partial_json);
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
case "content_block_stop": {
|
|
382
|
+
const t = u[w];
|
|
383
|
+
if (t?.type === "tool_use" && m) {
|
|
384
|
+
try {
|
|
385
|
+
t.input = JSON.parse(m);
|
|
386
|
+
} catch {
|
|
387
|
+
t.input = {};
|
|
388
|
+
}
|
|
389
|
+
m = "";
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
case "message_delta": {
|
|
394
|
+
const t = d.delta;
|
|
395
|
+
t.stop_reason && (x = t.stop_reason);
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (_.push({ role: "assistant", content: u }), x !== "tool_use")
|
|
400
|
+
break;
|
|
401
|
+
const g = [];
|
|
402
|
+
for (const d of u) {
|
|
403
|
+
if (d.type !== "tool_use") continue;
|
|
404
|
+
const t = d.name, h = d.input || {}, p = d.id, k = T.get(t);
|
|
405
|
+
if (!k) {
|
|
406
|
+
g.push({
|
|
407
|
+
type: "tool_result",
|
|
408
|
+
tool_use_id: p,
|
|
409
|
+
content: `Unknown tool: ${t}`,
|
|
410
|
+
is_error: !0
|
|
411
|
+
}), yield {
|
|
412
|
+
type: "tool_use_result",
|
|
413
|
+
data: { id: p, name: t, result: `Unknown tool: ${t}` }
|
|
414
|
+
};
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
const c = await k(h);
|
|
419
|
+
c.sideEffect && (yield c.sideEffect), g.push({
|
|
420
|
+
type: "tool_result",
|
|
421
|
+
tool_use_id: p,
|
|
422
|
+
content: c.result,
|
|
423
|
+
...c.isError ? { is_error: !0 } : {}
|
|
424
|
+
}), yield {
|
|
425
|
+
type: "tool_use_result",
|
|
426
|
+
data: { id: p, name: t, result: c.result }
|
|
427
|
+
};
|
|
428
|
+
} catch (c) {
|
|
429
|
+
const v = c instanceof Error ? c.message : "Tool execution failed";
|
|
430
|
+
g.push({
|
|
431
|
+
type: "tool_result",
|
|
432
|
+
tool_use_id: p,
|
|
433
|
+
content: v,
|
|
434
|
+
is_error: !0
|
|
435
|
+
}), yield {
|
|
436
|
+
type: "tool_use_result",
|
|
437
|
+
data: { id: p, name: t, result: v }
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
yield { type: "turn_complete", data: {} }, _.push({ role: "user", content: g });
|
|
442
|
+
}
|
|
443
|
+
yield {
|
|
444
|
+
type: "done",
|
|
445
|
+
data: { sessionId: a || "" }
|
|
446
|
+
};
|
|
447
|
+
} catch (l) {
|
|
448
|
+
yield {
|
|
449
|
+
type: "error",
|
|
450
|
+
data: {
|
|
451
|
+
message: l instanceof Error ? l.message : "Agent execution failed"
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
export {
|
|
457
|
+
J as handleAgentChat
|
|
458
|
+
};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("hono"),i=require("../mcp-transport-BB998cy5.cjs"),v=require("../utils.cjs");var D=w=>{const p={...{origin:"*",allowMethods:["GET","HEAD","PUT","POST","DELETE","PATCH"],allowHeaders:[],exposeHeaders:[]},...w},I=(y=>typeof y=="string"?y==="*"?()=>y:u=>y===u?u:null:typeof y=="function"?y:u=>y.includes(u)?u:null)(p.origin),m=(y=>typeof y=="function"?y:Array.isArray(y)?()=>y:()=>[])(p.allowMethods);return async function(u,h){function g(C,c){u.res.headers.set(C,c)}const b=await I(u.req.header("origin")||"",u);if(b&&g("Access-Control-Allow-Origin",b),p.credentials&&g("Access-Control-Allow-Credentials","true"),p.exposeHeaders?.length&&g("Access-Control-Expose-Headers",p.exposeHeaders.join(",")),u.req.method==="OPTIONS"){p.origin!=="*"&&g("Vary","Origin"),p.maxAge!=null&&g("Access-Control-Max-Age",p.maxAge.toString());const C=await m(u.req.header("origin")||"",u);C.length&&g("Access-Control-Allow-Methods",C.join(","));let c=p.allowHeaders;if(!c?.length){const s=u.req.header("Access-Control-Request-Headers");s&&(c=s.split(/\s*,\s*/))}return c?.length&&(g("Access-Control-Allow-Headers",c.join(",")),u.res.headers.append("Vary","Access-Control-Request-Headers")),u.res.headers.delete("Content-Length"),u.res.headers.delete("Content-Type"),new Response(null,{headers:u.res.headers,status:204,statusText:"No Content"})}await h(),p.origin!=="*"&&u.header("Vary","Origin",{append:!0})}};function O(w){const{cubes:j,drizzle:p,schema:I,extractSecurityContext:m,engineType:y,cors:u,basePath:h="/cubejs-api/v1",cache:g,mcp:b={enabled:!0},agent:C}=w;if(!j||j.length===0)throw new Error("At least one cube must be provided in the cubes array");const c=new N.Hono;u&&c.use("/*",D(u));const s=new i.SemanticLayerCompiler({drizzle:p,schema:I,engineType:y,cache:g});if(j.forEach(r=>{s.registerCube(r)}),c.post(`${h}/load`,async r=>{try{const e=await r.req.json(),n=e.query||e,o=await m(r),t=s.validateQuery(n);if(!t.isValid)return r.json({error:`Query validation failed: ${t.errors.join(", ")}`},400);const a=r.req.header("x-cache-control")==="no-cache",d=await s.executeMultiCubeQuery(n,o,{skipCache:a});return r.json(v.formatCubeResponse(n,d,s))}catch(e){return console.error("Query execution error:",e),r.json({error:e instanceof Error?e.message:"Query execution failed"},500)}}),c.get(`${h}/load`,async r=>{try{const e=r.req.query("query");if(!e)return r.json({error:"Query parameter is required"},400);let n;try{n=JSON.parse(e)}catch{return r.json({error:"Invalid JSON in query parameter"},400)}const o=await m(r),t=s.validateQuery(n);if(!t.isValid)return r.json({error:`Query validation failed: ${t.errors.join(", ")}`},400);const a=r.req.header("x-cache-control")==="no-cache",d=await s.executeMultiCubeQuery(n,o,{skipCache:a});return r.json(v.formatCubeResponse(n,d,s))}catch(e){return console.error("Query execution error:",e),r.json({error:e instanceof Error?e.message:"Query execution failed"},500)}}),c.post(`${h}/batch`,async r=>{try{const e=await r.req.json(),{queries:n}=e;if(!n||!Array.isArray(n))return r.json({error:'Request body must contain a "queries" array'},400);if(n.length===0)return r.json({error:"Queries array cannot be empty"},400);const o=await m(r),t=r.req.header("x-cache-control")==="no-cache",a=await v.handleBatchRequest(n,o,s,{skipCache:t});return r.json(a)}catch(e){return console.error("Batch execution error:",e),r.json({error:e instanceof Error?e.message:"Batch execution failed"},500)}}),c.get(`${h}/meta`,r=>{try{const e=s.getMetadata();return r.json(v.formatMetaResponse(e))}catch(e){return console.error("Metadata error:",e),r.json({error:e instanceof Error?e.message:"Failed to fetch metadata"},500)}}),c.post(`${h}/sql`,async r=>{try{const e=await r.req.json(),n=await m(r),o=s.validateQuery(e);if(!o.isValid)return r.json({error:`Query validation failed: ${o.errors.join(", ")}`},400);const t=e.measures?.[0]||e.dimensions?.[0];if(!t)return r.json({error:"No measures or dimensions specified"},400);const a=t.split(".")[0],d=await s.generateSQL(a,e,n);return r.json(v.formatSqlResponse(e,d))}catch(e){return console.error("SQL generation error:",e),r.json({error:e instanceof Error?e.message:"SQL generation failed"},500)}}),c.get(`${h}/sql`,async r=>{try{const e=r.req.query("query");if(!e)return r.json({error:"Query parameter is required"},400);const n=JSON.parse(e),o=await m(r),t=s.validateQuery(n);if(!t.isValid)return r.json({error:`Query validation failed: ${t.errors.join(", ")}`},400);const a=n.measures?.[0]||n.dimensions?.[0];if(!a)return r.json({error:"No measures or dimensions specified"},400);const d=a.split(".")[0],q=await s.generateSQL(d,n,o);return r.json(v.formatSqlResponse(n,q))}catch(e){return console.error("SQL generation error:",e),r.json({error:e instanceof Error?e.message:"SQL generation failed"},500)}}),c.post(`${h}/dry-run`,async r=>{try{const e=await r.req.json(),n=e.query||e,o=await m(r),t=await v.handleDryRun(n,o,s);return r.json(t)}catch(e){return console.error("Dry-run error:",e),r.json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1},400)}}),c.get(`${h}/dry-run`,async r=>{try{const e=r.req.query("query");if(!e)return r.json({error:"Query parameter is required",valid:!1},400);const n=JSON.parse(e),o=await m(r),t=await v.handleDryRun(n,o,s);return r.json(t)}catch(e){return console.error("Dry-run error:",e),r.json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1},400)}}),c.post(`${h}/explain`,async r=>{try{const e=await r.req.json(),n=e.query||e,o=e.options||{},t=await m(r),a=s.validateQuery(n);if(!a.isValid)return r.json({error:`Query validation failed: ${a.errors.join(", ")}`},400);const d=await s.explainQuery(n,t,o);return r.json(d)}catch(e){return console.error("Explain error:",e),r.json({error:e instanceof Error?e.message:"Explain query failed"},500)}}),C&&c.post(`${h}/agent/chat`,async r=>{try{const{handleAgentChat:e}=await Promise.resolve().then(()=>require("../handler-D6l8AbJV.cjs")),n=await r.req.json(),{message:o,sessionId:t}=n;if(!o||typeof o!="string")return r.json({error:"message is required and must be a string"},400);let a=(C.apiKey||"").trim();if(C.allowClientApiKey){const l=r.req.header("x-agent-api-key");l&&(a=l.trim())}if(!a)return r.json({error:"No API key configured. Set agent.apiKey in server config or send X-Agent-Api-Key header."},401);const d=await m(r),q=new TextEncoder,R=new ReadableStream({async start(l){try{const x=e({message:o,sessionId:t,semanticLayer:s,securityContext:d,agentConfig:C,apiKey:a});for await(const E of x){const f=`data: ${JSON.stringify(E)}
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`;l.enqueue(q.encode(f))}}catch(x){const E={type:"error",data:{message:x instanceof Error?x.message:"Stream failed"}};l.enqueue(q.encode(`data: ${JSON.stringify(E)}
|
|
4
4
|
|
|
5
|
-
`))
|
|
5
|
+
`))}finally{l.close()}}});return new Response(R,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}catch(e){return console.error("Agent chat error:",e),r.json({error:e instanceof Error?e.message:"Agent chat failed"},500)}}),b.enabled!==!1){const r={uri:"drizzle-cube://schema",name:"Cube Schema",description:"Current cube metadata as JSON",mimeType:"application/json",text:JSON.stringify(s.getMetadata(),null,2)},e=[...i.getDefaultResources(),r],n=i.getDefaultPrompts(),o=b.basePath??"/mcp";c.post(`${o}`,async t=>{const a=i.validateOriginHeader(t.req.header("origin"),b.allowedOrigins?{allowedOrigins:b.allowedOrigins}:{});if(!a.valid)return t.json(i.buildJsonRpcError(null,-32600,a.reason),403);const d=t.req.header("accept");if(!i.validateAcceptHeader(d))return t.json(i.buildJsonRpcError(null,-32600,"Accept header must include both application/json and text/event-stream"),400);const q=i.negotiateProtocol(t.req.header());if(!q.ok)return t.json({error:"Unsupported MCP protocol version",supported:q.supported},426);const R=await t.req.json().catch(()=>null),l=i.parseJsonRpc(R);if(!l)return t.json(i.buildJsonRpcError(null,-32600,"Invalid JSON-RPC 2.0 request"),400);const x=i.wantsEventStream(d),E=l.method==="initialize";try{const f=await i.dispatchMcpMethod(l.method,l.params,{semanticLayer:s,extractSecurityContext:m,rawRequest:t,rawResponse:null,negotiatedProtocol:q.negotiated,resources:e,prompts:n});if(i.isNotification(l))return t.body(null,202);const $=i.buildJsonRpcResult(l.id??null,f),T=E&&f&&typeof f=="object"&&"sessionId"in f?f.sessionId:void 0,S={};if(T&&(S[i.MCP_SESSION_ID_HEADER]=T),x){const A=new TextEncoder,Q=i.primeEventId(),H=new ReadableStream({start(P){P.enqueue(A.encode(`id: ${Q}
|
|
6
6
|
|
|
7
|
-
`))
|
|
7
|
+
`)),P.enqueue(A.encode(i.serializeSseEvent($,Q))),P.close()}});return new Response(H,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive",...S}})}return t.json($,200,S)}catch(f){if(i.isNotification(l))return console.error("MCP notification processing error:",f),t.body(null,202);console.error("MCP RPC error:",f);const $=f?.code??-32603,T=f?.data,S=f.message||"MCP request failed",A=i.buildJsonRpcError(l.id??null,$,S,T);if(x){const Q=new TextEncoder,H=i.primeEventId(),P=new ReadableStream({start(M){M.enqueue(Q.encode(`id: ${H}
|
|
8
|
+
|
|
9
|
+
`)),M.enqueue(Q.encode(i.serializeSseEvent(A,H))),M.close()}});return new Response(P,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}return t.json(A,200)}}),c.delete(`${o}`,t=>t.json({error:"Session termination not supported"},405)),c.get(`${o}`,t=>{const a=new TextEncoder,d=i.primeEventId();let q;const R=new ReadableStream({start(l){l.enqueue(a.encode(i.serializeSseEvent({jsonrpc:"2.0",method:"mcp/ready",params:{protocol:"streamable-http"}},d,15e3))),q=setInterval(()=>{l.enqueue(a.encode(`: keep-alive
|
|
10
|
+
|
|
11
|
+
`))},15e3)},cancel(){clearInterval(q)}});return new Response(R,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})})}return c}function J(w,j){const p=O(j);return w.route("/",p),w}function k(w){const j=new N.Hono;return J(j,w)}exports.createCubeApp=k;exports.createCubeRoutes=O;exports.mountCubeRoutes=J;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { SemanticQuery, SecurityContext, DatabaseExecutor, DrizzleDatabase, Cube, CacheConfig } from '../../server';
|
|
3
|
+
import { AgentConfig } from '../../server/agent/types';
|
|
3
4
|
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
4
5
|
import { MySql2Database } from 'drizzle-orm/mysql2';
|
|
5
6
|
import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
@@ -72,6 +73,12 @@ export interface HonoAdapterOptions {
|
|
|
72
73
|
* @default { enabled: true }
|
|
73
74
|
*/
|
|
74
75
|
mcp?: MCPOptions;
|
|
76
|
+
/**
|
|
77
|
+
* Agent configuration for the agentic AI notebook feature.
|
|
78
|
+
* When provided, enables the POST /agent/chat SSE endpoint.
|
|
79
|
+
* Requires `@anthropic-ai/sdk` as a peer dependency.
|
|
80
|
+
*/
|
|
81
|
+
agent?: AgentConfig;
|
|
75
82
|
}
|
|
76
83
|
/**
|
|
77
84
|
* Create Hono routes for Cube.js-compatible API
|