drizzle-cube 0.4.7 → 0.4.8

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 (122) hide show
  1. package/dist/adapters/express/index.cjs +1 -1
  2. package/dist/adapters/express/index.js +2 -2
  3. package/dist/adapters/fastify/index.cjs +1 -1
  4. package/dist/adapters/fastify/index.js +2 -2
  5. package/dist/adapters/handler-BLcxTuwi.cjs +23 -0
  6. package/dist/adapters/handler-odjn7MIB.js +1880 -0
  7. package/dist/adapters/hono/index.cjs +1 -1
  8. package/dist/adapters/hono/index.js +2 -2
  9. package/dist/adapters/{mcp-transport-DFTCWene.js → mcp-transport-CU5g9bxj.js} +3 -3
  10. package/dist/adapters/{mcp-transport-BB998cy5.cjs → mcp-transport-KX92EgkF.cjs} +2 -2
  11. package/dist/adapters/nextjs/index.cjs +2 -2
  12. package/dist/adapters/nextjs/index.js +3 -3
  13. package/dist/client/charts/chartConfigs.d.ts +2 -9
  14. package/dist/client/charts.js +72 -70
  15. package/dist/client/charts.js.map +1 -1
  16. package/dist/client/chunks/{RetentionCombinedChart.config-C-ILIaEb.js → RetentionCombinedChart.config-Bbp2ghim.js} +2 -1
  17. package/dist/client/chunks/RetentionCombinedChart.config-Bbp2ghim.js.map +1 -0
  18. package/dist/client/chunks/{RetentionHeatmap.config-CIvhc-GT.js → RetentionHeatmap.config-BWf_-vdj.js} +2 -1
  19. package/dist/client/chunks/RetentionHeatmap.config-BWf_-vdj.js.map +1 -0
  20. package/dist/client/chunks/{analysis-builder-Dn8xpgPQ.js → analysis-builder-Bov_gLsf.js} +1408 -1393
  21. package/dist/client/chunks/analysis-builder-Bov_gLsf.js.map +1 -0
  22. package/dist/client/chunks/{analysis-builder-shared-D3xYzXlh.js → analysis-builder-shared-NBk6y0md.js} +3 -3
  23. package/dist/client/chunks/{analysis-builder-shared-D3xYzXlh.js.map → analysis-builder-shared-NBk6y0md.js.map} +1 -1
  24. package/dist/client/chunks/{chart-activity-grid-DStNr34n.js → chart-activity-grid-CE7xGFQo.js} +2 -2
  25. package/dist/client/chunks/{chart-activity-grid-DStNr34n.js.map → chart-activity-grid-CE7xGFQo.js.map} +1 -1
  26. package/dist/client/chunks/chart-box-plot-Dja4LS3O.js +313 -0
  27. package/dist/client/chunks/chart-box-plot-Dja4LS3O.js.map +1 -0
  28. package/dist/client/chunks/{chart-config-activity-grid-CAlo1cHA.js → chart-config-activity-grid-CmOqDuOT.js} +4 -5
  29. package/dist/client/chunks/chart-config-activity-grid-CmOqDuOT.js.map +1 -0
  30. package/dist/client/chunks/{chart-config-area-CyyJOO2T.js → chart-config-area-CK_GVApT.js} +4 -5
  31. package/dist/client/chunks/chart-config-area-CK_GVApT.js.map +1 -0
  32. package/dist/client/chunks/{chart-config-bar-soxw6m2o.js → chart-config-bar-C8uzktxl.js} +4 -5
  33. package/dist/client/chunks/chart-config-bar-C8uzktxl.js.map +1 -0
  34. package/dist/client/chunks/chart-config-box-plot-D3DA7_pr.js +85 -0
  35. package/dist/client/chunks/chart-config-box-plot-D3DA7_pr.js.map +1 -0
  36. package/dist/client/chunks/{chart-config-bubble-CuSsCHZ4.js → chart-config-bubble-q3DoQX5F.js} +4 -5
  37. package/dist/client/chunks/chart-config-bubble-q3DoQX5F.js.map +1 -0
  38. package/dist/client/chunks/{chart-config-data-table-BhgqwoqT.js → chart-config-data-table-B20Y5JCm.js} +4 -5
  39. package/dist/client/chunks/chart-config-data-table-B20Y5JCm.js.map +1 -0
  40. package/dist/client/chunks/{chart-config-funnel-BlSQYng0.js → chart-config-funnel-3eYnGg8M.js} +4 -5
  41. package/dist/client/chunks/chart-config-funnel-3eYnGg8M.js.map +1 -0
  42. package/dist/client/chunks/{chart-config-heat-map-DHQGFZhX.js → chart-config-heat-map-_wEnTnRA.js} +4 -5
  43. package/dist/client/chunks/chart-config-heat-map-_wEnTnRA.js.map +1 -0
  44. package/dist/client/chunks/{chart-config-kpi-delta-yTA5ug_l.js → chart-config-kpi-delta-DLGZ2A3X.js} +4 -5
  45. package/dist/client/chunks/chart-config-kpi-delta-DLGZ2A3X.js.map +1 -0
  46. package/dist/client/chunks/{chart-config-kpi-number-nVAwDXzq.js → chart-config-kpi-number-K-wzviXF.js} +4 -5
  47. package/dist/client/chunks/chart-config-kpi-number-K-wzviXF.js.map +1 -0
  48. package/dist/client/chunks/{chart-config-kpi-text-DZjqsx-b.js → chart-config-kpi-text-BjYqwqaJ.js} +4 -5
  49. package/dist/client/chunks/chart-config-kpi-text-BjYqwqaJ.js.map +1 -0
  50. package/dist/client/chunks/{chart-config-line-D5ME6w0v.js → chart-config-line-JNagi9tf.js} +4 -5
  51. package/dist/client/chunks/chart-config-line-JNagi9tf.js.map +1 -0
  52. package/dist/client/chunks/{chart-config-markdown-BXKL5TbQ.js → chart-config-markdown-BWQSjJpy.js} +4 -5
  53. package/dist/client/chunks/chart-config-markdown-BWQSjJpy.js.map +1 -0
  54. package/dist/client/chunks/{chart-config-pie-DlHa2jTy.js → chart-config-pie-CNLXb-fr.js} +4 -5
  55. package/dist/client/chunks/chart-config-pie-CNLXb-fr.js.map +1 -0
  56. package/dist/client/chunks/{chart-config-radar-BBAVIF0S.js → chart-config-radar-oxHfRAa3.js} +4 -5
  57. package/dist/client/chunks/chart-config-radar-oxHfRAa3.js.map +1 -0
  58. package/dist/client/chunks/{chart-config-radial-bar-CTwjDRnB.js → chart-config-radial-bar-_Aw3jAEm.js} +4 -5
  59. package/dist/client/chunks/chart-config-radial-bar-_Aw3jAEm.js.map +1 -0
  60. package/dist/client/chunks/{chart-config-sankey-CNAgsMQ4.js → chart-config-sankey-C8FX9hGF.js} +4 -5
  61. package/dist/client/chunks/chart-config-sankey-C8FX9hGF.js.map +1 -0
  62. package/dist/client/chunks/{chart-config-scatter-CWvN2E-X.js → chart-config-scatter-DFKM80eO.js} +4 -5
  63. package/dist/client/chunks/chart-config-scatter-DFKM80eO.js.map +1 -0
  64. package/dist/client/chunks/{chart-config-sunburst-W_SKwaj0.js → chart-config-sunburst-BmC0NLTU.js} +4 -5
  65. package/dist/client/chunks/chart-config-sunburst-BmC0NLTU.js.map +1 -0
  66. package/dist/client/chunks/{chart-config-tree-map-IRAYf9YM.js → chart-config-tree-map-DGMbNTaa.js} +4 -5
  67. package/dist/client/chunks/chart-config-tree-map-DGMbNTaa.js.map +1 -0
  68. package/dist/client/chunks/{chart-data-table-Ch_1c1Zo.js → chart-data-table-Ba_6tuJw.js} +2 -2
  69. package/dist/client/chunks/{chart-data-table-Ch_1c1Zo.js.map → chart-data-table-Ba_6tuJw.js.map} +1 -1
  70. package/dist/client/chunks/{chart-kpi-delta-CWCmi8vL.js → chart-kpi-delta-D9XJoKuA.js} +3 -3
  71. package/dist/client/chunks/{chart-kpi-delta-CWCmi8vL.js.map → chart-kpi-delta-D9XJoKuA.js.map} +1 -1
  72. package/dist/client/chunks/{chart-kpi-number-C-5m3qt5.js → chart-kpi-number-C29Vj2g8.js} +2 -2
  73. package/dist/client/chunks/{chart-kpi-number-C-5m3qt5.js.map → chart-kpi-number-C29Vj2g8.js.map} +1 -1
  74. package/dist/client/chunks/{chart-kpi-text--t4ibPmx.js → chart-kpi-text-CgjjrurK.js} +2 -2
  75. package/dist/client/chunks/{chart-kpi-text--t4ibPmx.js.map → chart-kpi-text-CgjjrurK.js.map} +1 -1
  76. package/dist/client/chunks/{charts-loader-DcFWOUeV.js → charts-loader-HYQFVOo4.js} +13 -12
  77. package/dist/client/chunks/charts-loader-HYQFVOo4.js.map +1 -0
  78. package/dist/client/chunks/{components-Bdt1AmzS.js → components-O0hh7ooo.js} +5 -5
  79. package/dist/client/chunks/components-O0hh7ooo.js.map +1 -0
  80. package/dist/client/chunks/{icons-DRreo6m8.js → icons-DAeqv1iX.js} +7 -7
  81. package/dist/client/chunks/{icons-DRreo6m8.js.map → icons-DAeqv1iX.js.map} +1 -1
  82. package/dist/client/components/charts/BoxPlotChart.config.d.ts +11 -0
  83. package/dist/client/components/charts/BoxPlotChart.d.ts +4 -0
  84. package/dist/client/components/charts/index.d.ts +1 -0
  85. package/dist/client/components.js +1 -1
  86. package/dist/client/icons.js +1 -1
  87. package/dist/client/index.js +7 -7
  88. package/dist/client/index.js.map +1 -1
  89. package/dist/client/types.d.ts +1 -1
  90. package/dist/client/utils.js +3 -3
  91. package/dist/client-bundle-stats.html +4 -4
  92. package/dist/server/index.cjs +118 -102
  93. package/dist/server/index.js +6161 -4739
  94. package/package.json +6 -6
  95. package/dist/adapters/handler-D6l8AbJV.cjs +0 -7
  96. package/dist/adapters/handler-DsNgnIPK.js +0 -458
  97. package/dist/client/chunks/RetentionCombinedChart.config-C-ILIaEb.js.map +0 -1
  98. package/dist/client/chunks/RetentionHeatmap.config-CIvhc-GT.js.map +0 -1
  99. package/dist/client/chunks/analysis-builder-Dn8xpgPQ.js.map +0 -1
  100. package/dist/client/chunks/chart-config-activity-grid-CAlo1cHA.js.map +0 -1
  101. package/dist/client/chunks/chart-config-area-CyyJOO2T.js.map +0 -1
  102. package/dist/client/chunks/chart-config-bar-soxw6m2o.js.map +0 -1
  103. package/dist/client/chunks/chart-config-bubble-CuSsCHZ4.js.map +0 -1
  104. package/dist/client/chunks/chart-config-data-table-BhgqwoqT.js.map +0 -1
  105. package/dist/client/chunks/chart-config-funnel-BlSQYng0.js.map +0 -1
  106. package/dist/client/chunks/chart-config-heat-map-DHQGFZhX.js.map +0 -1
  107. package/dist/client/chunks/chart-config-kpi-delta-yTA5ug_l.js.map +0 -1
  108. package/dist/client/chunks/chart-config-kpi-number-nVAwDXzq.js.map +0 -1
  109. package/dist/client/chunks/chart-config-kpi-text-DZjqsx-b.js.map +0 -1
  110. package/dist/client/chunks/chart-config-line-D5ME6w0v.js.map +0 -1
  111. package/dist/client/chunks/chart-config-markdown-BXKL5TbQ.js.map +0 -1
  112. package/dist/client/chunks/chart-config-pie-DlHa2jTy.js.map +0 -1
  113. package/dist/client/chunks/chart-config-radar-BBAVIF0S.js.map +0 -1
  114. package/dist/client/chunks/chart-config-radial-bar-CTwjDRnB.js.map +0 -1
  115. package/dist/client/chunks/chart-config-sankey-CNAgsMQ4.js.map +0 -1
  116. package/dist/client/chunks/chart-config-scatter-CWvN2E-X.js.map +0 -1
  117. package/dist/client/chunks/chart-config-sunburst-W_SKwaj0.js.map +0 -1
  118. package/dist/client/chunks/chart-config-tree-map-IRAYf9YM.js.map +0 -1
  119. package/dist/client/chunks/chartConfigRegistry-C5dZm-ZK.js +0 -44
  120. package/dist/client/chunks/chartConfigRegistry-C5dZm-ZK.js.map +0 -1
  121. package/dist/client/chunks/charts-loader-DcFWOUeV.js.map +0 -1
  122. package/dist/client/chunks/components-Bdt1AmzS.js.map +0 -1
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("express"),M=require("cors"),c=require("../mcp-transport-BB998cy5.cjs"),n=require("../utils.cjs");function $(g){const{cubes:m,drizzle:w,schema:P,extractSecurityContext:y,engineType:A,cors:x,basePath:f="/cubejs-api/v1",jsonLimit:S="10mb",cache:H,mcp:v={enabled:!0},agent:j}=g;if(!m||m.length===0)throw new Error("At least one cube must be provided in the cubes array");const d=R.Router();x&&d.use(M(x)),d.use(R.json({limit:S})),d.use(R.urlencoded({extended:!0,limit:S}));const u=new c.SemanticLayerCompiler({drizzle:w,schema:P,engineType:A,cache:H});if(m.forEach(r=>{u.registerCube(r)}),d.post(`${f}/load`,async(r,t)=>{try{const e=r.body.query||r.body,o=await y(r,t),a=u.validateQuery(e);if(!a.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${a.errors.join(", ")}`,400));const s=r.headers["x-cache-control"]==="no-cache",i=await u.executeMultiCubeQuery(e,o,{skipCache:s});t.json(n.formatCubeResponse(e,i,u))}catch(e){console.error("Query execution error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),d.get(`${f}/load`,async(r,t)=>{try{const e=r.query.query;if(!e)return t.status(400).json(n.formatErrorResponse("Query parameter is required",400));let o;try{o=JSON.parse(e)}catch{return t.status(400).json(n.formatErrorResponse("Invalid JSON in query parameter",400))}const a=await y(r,t),s=u.validateQuery(o);if(!s.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${s.errors.join(", ")}`,400));const i=r.headers["x-cache-control"]==="no-cache",l=await u.executeMultiCubeQuery(o,a,{skipCache:i});t.json(n.formatCubeResponse(o,l,u))}catch(e){console.error("Query execution error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),d.post(`${f}/batch`,async(r,t)=>{try{const{queries:e}=r.body;if(!e||!Array.isArray(e))return t.status(400).json(n.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return t.status(400).json(n.formatErrorResponse("Queries array cannot be empty",400));const o=await y(r,t),a=r.headers["x-cache-control"]==="no-cache",s=await n.handleBatchRequest(e,o,u,{skipCache:a});t.json(s)}catch(e){console.error("Batch execution error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),d.get(`${f}/meta`,(r,t)=>{try{const e=u.getMetadata();t.json(n.formatMetaResponse(e))}catch(e){console.error("Metadata error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),d.post(`${f}/sql`,async(r,t)=>{try{const e=r.body,o=await y(r,t),a=u.validateQuery(e);if(!a.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${a.errors.join(", ")}`,400));const s=e.measures?.[0]||e.dimensions?.[0];if(!s)return t.status(400).json(n.formatErrorResponse("No measures or dimensions specified",400));const i=s.split(".")[0],l=await u.generateSQL(i,e,o);t.json(n.formatSqlResponse(e,l))}catch(e){console.error("SQL generation error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),d.get(`${f}/sql`,async(r,t)=>{try{const e=r.query.query;if(!e)return t.status(400).json(n.formatErrorResponse("Query parameter is required",400));const o=JSON.parse(e),a=await y(r,t),s=u.validateQuery(o);if(!s.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${s.errors.join(", ")}`,400));const i=o.measures?.[0]||o.dimensions?.[0];if(!i)return t.status(400).json(n.formatErrorResponse("No measures or dimensions specified",400));const l=i.split(".")[0],h=await u.generateSQL(l,o,a);t.json(n.formatSqlResponse(o,h))}catch(e){console.error("SQL generation error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),d.post(`${f}/dry-run`,async(r,t)=>{try{const e=r.body.query||r.body,o=await y(r,t),a=await n.handleDryRun(e,o,u);t.json(a)}catch(e){console.error("Dry-run error:",e),t.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),d.get(`${f}/dry-run`,async(r,t)=>{try{const e=r.query.query;if(!e)return t.status(400).json({error:"Query parameter is required",valid:!1});const o=JSON.parse(e),a=await y(r,t),s=await n.handleDryRun(o,a,u);t.json(s)}catch(e){console.error("Dry-run error:",e),t.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),d.post(`${f}/explain`,async(r,t)=>{try{const e=r.body.query||r.body,o=r.body.options||{},a=await y(r,t),s=u.validateQuery(e);if(!s.isValid)return t.status(400).json({error:`Query validation failed: ${s.errors.join(", ")}`});const i=await u.explainQuery(e,a,o);t.json(i)}catch(e){console.error("Explain error:",e),t.status(500).json({error:e instanceof Error?e.message:"Explain query failed"})}}),j&&d.post(`${f}/agent/chat`,async(r,t)=>{try{const{handleAgentChat:e}=await Promise.resolve().then(()=>require("../handler-D6l8AbJV.cjs")),{message:o,sessionId:a}=r.body;if(!o||typeof o!="string")return t.status(400).json({error:"message is required and must be a string"});let s=(j.apiKey||"").trim();if(j.allowClientApiKey){const l=r.headers["x-agent-api-key"];l&&(s=l.trim())}if(!s)return t.status(401).json({error:"No API key configured. Set agent.apiKey in server config or send X-Agent-Api-Key header."});const i=await y(r,t);t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});try{const l=e({message:o,sessionId:a,semanticLayer:u,securityContext:i,agentConfig:j,apiKey:s});for await(const h of l)t.write(`data: ${JSON.stringify(h)}
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("express"),M=require("cors"),c=require("../mcp-transport-KX92EgkF.cjs"),n=require("../utils.cjs");function $(g){const{cubes:m,drizzle:w,schema:P,extractSecurityContext:y,engineType:A,cors:x,basePath:f="/cubejs-api/v1",jsonLimit:S="10mb",cache:H,mcp:v={enabled:!0},agent:j}=g;if(!m||m.length===0)throw new Error("At least one cube must be provided in the cubes array");const d=R.Router();x&&d.use(M(x)),d.use(R.json({limit:S})),d.use(R.urlencoded({extended:!0,limit:S}));const u=new c.SemanticLayerCompiler({drizzle:w,schema:P,engineType:A,cache:H});if(m.forEach(r=>{u.registerCube(r)}),d.post(`${f}/load`,async(r,t)=>{try{const e=r.body.query||r.body,o=await y(r,t),a=u.validateQuery(e);if(!a.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${a.errors.join(", ")}`,400));const s=r.headers["x-cache-control"]==="no-cache",i=await u.executeMultiCubeQuery(e,o,{skipCache:s});t.json(n.formatCubeResponse(e,i,u))}catch(e){console.error("Query execution error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),d.get(`${f}/load`,async(r,t)=>{try{const e=r.query.query;if(!e)return t.status(400).json(n.formatErrorResponse("Query parameter is required",400));let o;try{o=JSON.parse(e)}catch{return t.status(400).json(n.formatErrorResponse("Invalid JSON in query parameter",400))}const a=await y(r,t),s=u.validateQuery(o);if(!s.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${s.errors.join(", ")}`,400));const i=r.headers["x-cache-control"]==="no-cache",l=await u.executeMultiCubeQuery(o,a,{skipCache:i});t.json(n.formatCubeResponse(o,l,u))}catch(e){console.error("Query execution error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),d.post(`${f}/batch`,async(r,t)=>{try{const{queries:e}=r.body;if(!e||!Array.isArray(e))return t.status(400).json(n.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return t.status(400).json(n.formatErrorResponse("Queries array cannot be empty",400));const o=await y(r,t),a=r.headers["x-cache-control"]==="no-cache",s=await n.handleBatchRequest(e,o,u,{skipCache:a});t.json(s)}catch(e){console.error("Batch execution error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),d.get(`${f}/meta`,(r,t)=>{try{const e=u.getMetadata();t.json(n.formatMetaResponse(e))}catch(e){console.error("Metadata error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),d.post(`${f}/sql`,async(r,t)=>{try{const e=r.body,o=await y(r,t),a=u.validateQuery(e);if(!a.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${a.errors.join(", ")}`,400));const s=e.measures?.[0]||e.dimensions?.[0];if(!s)return t.status(400).json(n.formatErrorResponse("No measures or dimensions specified",400));const i=s.split(".")[0],l=await u.generateSQL(i,e,o);t.json(n.formatSqlResponse(e,l))}catch(e){console.error("SQL generation error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),d.get(`${f}/sql`,async(r,t)=>{try{const e=r.query.query;if(!e)return t.status(400).json(n.formatErrorResponse("Query parameter is required",400));const o=JSON.parse(e),a=await y(r,t),s=u.validateQuery(o);if(!s.isValid)return t.status(400).json(n.formatErrorResponse(`Query validation failed: ${s.errors.join(", ")}`,400));const i=o.measures?.[0]||o.dimensions?.[0];if(!i)return t.status(400).json(n.formatErrorResponse("No measures or dimensions specified",400));const l=i.split(".")[0],h=await u.generateSQL(l,o,a);t.json(n.formatSqlResponse(o,h))}catch(e){console.error("SQL generation error:",e),t.status(500).json(n.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),d.post(`${f}/dry-run`,async(r,t)=>{try{const e=r.body.query||r.body,o=await y(r,t),a=await n.handleDryRun(e,o,u);t.json(a)}catch(e){console.error("Dry-run error:",e),t.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),d.get(`${f}/dry-run`,async(r,t)=>{try{const e=r.query.query;if(!e)return t.status(400).json({error:"Query parameter is required",valid:!1});const o=JSON.parse(e),a=await y(r,t),s=await n.handleDryRun(o,a,u);t.json(s)}catch(e){console.error("Dry-run error:",e),t.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),d.post(`${f}/explain`,async(r,t)=>{try{const e=r.body.query||r.body,o=r.body.options||{},a=await y(r,t),s=u.validateQuery(e);if(!s.isValid)return t.status(400).json({error:`Query validation failed: ${s.errors.join(", ")}`});const i=await u.explainQuery(e,a,o);t.json(i)}catch(e){console.error("Explain error:",e),t.status(500).json({error:e instanceof Error?e.message:"Explain query failed"})}}),j&&d.post(`${f}/agent/chat`,async(r,t)=>{try{const{handleAgentChat:e}=await Promise.resolve().then(()=>require("../handler-BLcxTuwi.cjs")),{message:o,sessionId:a}=r.body;if(!o||typeof o!="string")return t.status(400).json({error:"message is required and must be a string"});let s=(j.apiKey||"").trim();if(j.allowClientApiKey){const l=r.headers["x-agent-api-key"];l&&(s=l.trim())}if(!s)return t.status(401).json({error:"No API key configured. Set agent.apiKey in server config or send X-Agent-Api-Key header."});const i=await y(r,t);t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});try{const l=e({message:o,sessionId:a,semanticLayer:u,securityContext:i,agentConfig:j,apiKey:s});for await(const h of l)t.write(`data: ${JSON.stringify(h)}
2
2
 
3
3
  `)}catch(l){const h={type:"error",data:{message:l instanceof Error?l.message:"Stream failed"}};t.write(`data: ${JSON.stringify(h)}
4
4
 
@@ -1,6 +1,6 @@
1
1
  import E, { Router as J } from "express";
2
2
  import L from "cors";
3
- import { S as D, v as _, b as w, a as K, n as V, p as z, w as T, d as B, i as P, M as F, c as U, e as S, s as Q } from "../mcp-transport-DFTCWene.js";
3
+ import { S as D, v as _, b as w, a as K, n as V, p as z, w as T, d as B, i as P, M as F, c as U, e as S, s as Q } from "../mcp-transport-CU5g9bxj.js";
4
4
  import { formatErrorResponse as u, formatCubeResponse as A, handleBatchRequest as X, formatMetaResponse as G, formatSqlResponse as H, handleDryRun as M } from "../utils.js";
5
5
  function W(h) {
6
6
  const {
@@ -198,7 +198,7 @@ function W(h) {
198
198
  }
199
199
  }), j && c.post(`${p}/agent/chat`, async (r, t) => {
200
200
  try {
201
- const { handleAgentChat: e } = await import("../handler-DsNgnIPK.js"), { message: o, sessionId: n } = r.body;
201
+ const { handleAgentChat: e } = await import("../handler-odjn7MIB.js"), { message: o, sessionId: n } = r.body;
202
202
  if (!o || typeof o != "string")
203
203
  return t.status(400).json({ error: "message is required and must be a string" });
204
204
  let a = (j.apiKey || "").trim();
@@ -1,4 +1,4 @@
1
- "use strict";var O=Object.create;var j=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var L=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty;var H=(l,n,b,C)=>{if(n&&typeof n=="object"||typeof n=="function")for(let f of J(n))!D.call(l,f)&&f!==b&&j(l,f,{get:()=>n[f],enumerable:!(C=k(n,f))||C.enumerable});return l};var T=(l,n,b)=>(b=l!=null?O(L(l)):{},H(n||!l||!l.__esModule?j(b,"default",{value:l,enumerable:!0}):b,l));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("../mcp-transport-BB998cy5.cjs"),i=require("../utils.cjs"),q=function(n,b,C){const{cubes:f,drizzle:I,schema:A,extractSecurityContext:g,engineType:M,cors:P,basePath:h="/cubejs-api/v1",bodyLimit:v=10485760,cache:N,mcp:E={enabled:!0},agent:R}=b;if(!f||f.length===0)return C(new Error("At least one cube must be provided in the cubes array"));P&&n.register(import("@fastify/cors"),P),n.addHook("onRequest",async(r,t)=>{r.method==="POST"&&(r.body=void 0)});const d=new u.SemanticLayerCompiler({drizzle:I,schema:A,engineType:M,cache:N});if(f.forEach(r=>{d.registerCube(r)}),n.post(`${h}/load`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=e.query||e,s=await g(r),c=d.validateQuery(o);if(!c.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const a=r.headers["x-cache-control"]==="no-cache",y=await d.executeMultiCubeQuery(o,s,{skipCache:a});return i.formatCubeResponse(o,y,d)}catch(e){return r.log.error(e,"Query execution error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.get(`${h}/load`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,t)=>{try{const{query:e}=r.query;let o;try{o=JSON.parse(e)}catch{return t.status(400).send(i.formatErrorResponse("Invalid JSON in query parameter",400))}const s=await g(r),c=d.validateQuery(o);if(!c.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const a=r.headers["x-cache-control"]==="no-cache",y=await d.executeMultiCubeQuery(o,s,{skipCache:a});return i.formatCubeResponse(o,y,d)}catch(e){return r.log.error(e,"Query execution error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.post(`${h}/batch`,{bodyLimit:v,schema:{body:{type:"object",required:["queries"],properties:{queries:{type:"array",items:{type:"object"}}}}}},async(r,t)=>{try{const{queries:e}=r.body;if(!e||!Array.isArray(e))return t.status(400).send(i.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return t.status(400).send(i.formatErrorResponse("Queries array cannot be empty",400));const o=await g(r),s=r.headers["x-cache-control"]==="no-cache";return await i.handleBatchRequest(e,o,d,{skipCache:s})}catch(e){return r.log.error(e,"Batch execution error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),n.get(`${h}/meta`,async(r,t)=>{try{const e=d.getMetadata();return i.formatMetaResponse(e)}catch(e){return r.log.error(e,"Metadata error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),n.post(`${h}/sql`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=await g(r),s=d.validateQuery(e);if(!s.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${s.errors.join(", ")}`,400));const c=e.measures?.[0]||e.dimensions?.[0];if(!c)return t.status(400).send(i.formatErrorResponse("No measures or dimensions specified",400));const a=c.split(".")[0],y=await d.generateSQL(a,e,o);return i.formatSqlResponse(e,y)}catch(e){return r.log.error(e,"SQL generation error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.get(`${h}/sql`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,t)=>{try{const{query:e}=r.query,o=JSON.parse(e),s=await g(r),c=d.validateQuery(o);if(!c.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const a=o.measures?.[0]||o.dimensions?.[0];if(!a)return t.status(400).send(i.formatErrorResponse("No measures or dimensions specified",400));const y=a.split(".")[0],m=await d.generateSQL(y,o,s);return i.formatSqlResponse(o,m)}catch(e){return r.log.error(e,"SQL generation error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.post(`${h}/dry-run`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=e.query||e,s=await g(r);return await i.handleDryRun(o,s,d)}catch(e){return r.log.error(e,"Dry-run error"),t.status(400).send({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),n.get(`${h}/dry-run`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,t)=>{try{const{query:e}=r.query,o=JSON.parse(e),s=await g(r);return await i.handleDryRun(o,s,d)}catch(e){return r.log.error(e,"Dry-run error"),t.status(400).send({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),n.post(`${h}/explain`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=e.query||e,s=e.options||{},c=await g(r),a=d.validateQuery(o);return a.isValid?await d.explainQuery(o,c,s):t.status(400).send({error:`Query validation failed: ${a.errors.join(", ")}`})}catch(e){return r.log.error(e,"Explain error"),t.status(500).send({error:e instanceof Error?e.message:"Explain query failed"})}}),R&&n.post(`${h}/agent/chat`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const{handleAgentChat:e}=await Promise.resolve().then(()=>require("../handler-D6l8AbJV.cjs")),o=r.body,{message:s,sessionId:c}=o;if(!s||typeof s!="string")return t.status(400).send({error:"message is required and must be a string"});let a=(R.apiKey||"").trim();if(R.allowClientApiKey){const m=r.headers["x-agent-api-key"];m&&(a=m.trim())}if(!a)return t.status(401).send({error:"No API key configured. Set agent.apiKey in server config or send X-Agent-Api-Key header."});const y=await g(r);t.raw.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});try{const m=e({message:s,sessionId:c,semanticLayer:d,securityContext:y,agentConfig:R,apiKey:a});for await(const p of m)t.raw.write(`data: ${JSON.stringify(p)}
1
+ "use strict";var O=Object.create;var j=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var L=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty;var H=(l,n,b,C)=>{if(n&&typeof n=="object"||typeof n=="function")for(let f of J(n))!D.call(l,f)&&f!==b&&j(l,f,{get:()=>n[f],enumerable:!(C=k(n,f))||C.enumerable});return l};var T=(l,n,b)=>(b=l!=null?O(L(l)):{},H(n||!l||!l.__esModule?j(b,"default",{value:l,enumerable:!0}):b,l));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("../mcp-transport-KX92EgkF.cjs"),i=require("../utils.cjs"),q=function(n,b,C){const{cubes:f,drizzle:I,schema:A,extractSecurityContext:g,engineType:M,cors:P,basePath:h="/cubejs-api/v1",bodyLimit:v=10485760,cache:N,mcp:E={enabled:!0},agent:R}=b;if(!f||f.length===0)return C(new Error("At least one cube must be provided in the cubes array"));P&&n.register(import("@fastify/cors"),P),n.addHook("onRequest",async(r,t)=>{r.method==="POST"&&(r.body=void 0)});const d=new u.SemanticLayerCompiler({drizzle:I,schema:A,engineType:M,cache:N});if(f.forEach(r=>{d.registerCube(r)}),n.post(`${h}/load`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=e.query||e,s=await g(r),c=d.validateQuery(o);if(!c.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const a=r.headers["x-cache-control"]==="no-cache",y=await d.executeMultiCubeQuery(o,s,{skipCache:a});return i.formatCubeResponse(o,y,d)}catch(e){return r.log.error(e,"Query execution error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.get(`${h}/load`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,t)=>{try{const{query:e}=r.query;let o;try{o=JSON.parse(e)}catch{return t.status(400).send(i.formatErrorResponse("Invalid JSON in query parameter",400))}const s=await g(r),c=d.validateQuery(o);if(!c.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const a=r.headers["x-cache-control"]==="no-cache",y=await d.executeMultiCubeQuery(o,s,{skipCache:a});return i.formatCubeResponse(o,y,d)}catch(e){return r.log.error(e,"Query execution error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.post(`${h}/batch`,{bodyLimit:v,schema:{body:{type:"object",required:["queries"],properties:{queries:{type:"array",items:{type:"object"}}}}}},async(r,t)=>{try{const{queries:e}=r.body;if(!e||!Array.isArray(e))return t.status(400).send(i.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return t.status(400).send(i.formatErrorResponse("Queries array cannot be empty",400));const o=await g(r),s=r.headers["x-cache-control"]==="no-cache";return await i.handleBatchRequest(e,o,d,{skipCache:s})}catch(e){return r.log.error(e,"Batch execution error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),n.get(`${h}/meta`,async(r,t)=>{try{const e=d.getMetadata();return i.formatMetaResponse(e)}catch(e){return r.log.error(e,"Metadata error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),n.post(`${h}/sql`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=await g(r),s=d.validateQuery(e);if(!s.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${s.errors.join(", ")}`,400));const c=e.measures?.[0]||e.dimensions?.[0];if(!c)return t.status(400).send(i.formatErrorResponse("No measures or dimensions specified",400));const a=c.split(".")[0],y=await d.generateSQL(a,e,o);return i.formatSqlResponse(e,y)}catch(e){return r.log.error(e,"SQL generation error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.get(`${h}/sql`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,t)=>{try{const{query:e}=r.query,o=JSON.parse(e),s=await g(r),c=d.validateQuery(o);if(!c.isValid)return t.status(400).send(i.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const a=o.measures?.[0]||o.dimensions?.[0];if(!a)return t.status(400).send(i.formatErrorResponse("No measures or dimensions specified",400));const y=a.split(".")[0],m=await d.generateSQL(y,o,s);return i.formatSqlResponse(o,m)}catch(e){return r.log.error(e,"SQL generation error"),t.status(500).send(i.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.post(`${h}/dry-run`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=e.query||e,s=await g(r);return await i.handleDryRun(o,s,d)}catch(e){return r.log.error(e,"Dry-run error"),t.status(400).send({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),n.get(`${h}/dry-run`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,t)=>{try{const{query:e}=r.query,o=JSON.parse(e),s=await g(r);return await i.handleDryRun(o,s,d)}catch(e){return r.log.error(e,"Dry-run error"),t.status(400).send({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),n.post(`${h}/explain`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const e=r.body,o=e.query||e,s=e.options||{},c=await g(r),a=d.validateQuery(o);return a.isValid?await d.explainQuery(o,c,s):t.status(400).send({error:`Query validation failed: ${a.errors.join(", ")}`})}catch(e){return r.log.error(e,"Explain error"),t.status(500).send({error:e instanceof Error?e.message:"Explain query failed"})}}),R&&n.post(`${h}/agent/chat`,{bodyLimit:v,schema:{body:{type:"object",additionalProperties:!0}}},async(r,t)=>{try{const{handleAgentChat:e}=await Promise.resolve().then(()=>require("../handler-BLcxTuwi.cjs")),o=r.body,{message:s,sessionId:c}=o;if(!s||typeof s!="string")return t.status(400).send({error:"message is required and must be a string"});let a=(R.apiKey||"").trim();if(R.allowClientApiKey){const m=r.headers["x-agent-api-key"];m&&(a=m.trim())}if(!a)return t.status(401).send({error:"No API key configured. Set agent.apiKey in server config or send X-Agent-Api-Key header."});const y=await g(r);t.raw.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});try{const m=e({message:s,sessionId:c,semanticLayer:d,securityContext:y,agentConfig:R,apiKey:a});for await(const p of m)t.raw.write(`data: ${JSON.stringify(p)}
2
2
 
3
3
  `)}catch(m){const p={type:"error",data:{message:m instanceof Error?m.message:"Stream failed"}};t.raw.write(`data: ${JSON.stringify(p)}
4
4
 
@@ -1,4 +1,4 @@
1
- import { S as D, v as K, b as x, a as T, n as V, p as z, w as _, d as B, i as j, M as F, c as U, e as E, s as P } from "../mcp-transport-DFTCWene.js";
1
+ import { S as D, v as K, b as x, a as T, n as V, p as z, w as _, d as B, i as j, M as F, c as U, e as E, s as P } from "../mcp-transport-CU5g9bxj.js";
2
2
  import { formatErrorResponse as d, formatCubeResponse as A, handleBatchRequest as X, formatMetaResponse as G, formatSqlResponse as I, handleDryRun as M } from "../utils.js";
3
3
  const N = function(i, k, R) {
4
4
  const {
@@ -262,7 +262,7 @@ const N = function(i, k, R) {
262
262
  }
263
263
  }, async (t, r) => {
264
264
  try {
265
- const { handleAgentChat: e } = await import("../handler-DsNgnIPK.js"), a = t.body, { message: n, sessionId: o } = a;
265
+ const { handleAgentChat: e } = await import("../handler-odjn7MIB.js"), a = t.body, { message: n, sessionId: o } = a;
266
266
  if (!n || typeof n != "string")
267
267
  return r.status(400).send({ error: "message is required and must be a string" });
268
268
  let s = (f.apiKey || "").trim();
@@ -0,0 +1,23 @@
1
+ "use strict";var N=Object.create;var E=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty;var H=(o,e,a,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of L(e))!R.call(o,t)&&t!==a&&E(o,t,{get:()=>e[t],enumerable:!(i=Y(e,t))||i.enumerable});return o};var $=(o,e,a)=>(a=o!=null?N(M(o)):{},H(e||!o||!o.__esModule?E(a,"default",{value:o,enumerable:!0}):a,o));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("./mcp-transport-KX92EgkF.cjs"),q=require("./utils.cjs");function B(o){if(o.length===0)return"No cubes are currently available.";const e=["## Available Cubes",""];for(const a of o){if(e.push(`### ${a.name}`),a.description&&e.push(a.description),a.measures&&a.measures.length>0){e.push(""),e.push("**Measures:**");for(const i of a.measures){const t=i.description?` - ${i.description}`:"";e.push(`- \`${a.name}.${i.name}\` (${i.type})${t}`)}}if(a.dimensions&&a.dimensions.length>0){e.push(""),e.push("**Dimensions:**");for(const i of a.dimensions){const t=i.description?` - ${i.description}`:"";e.push(`- \`${a.name}.${i.name}\` (${i.type})${t}`)}}if(a.relationships&&a.relationships.length>0){e.push(""),e.push("**Joins:**");for(const i of a.relationships)e.push(`- → \`${i.targetCube}\` (${i.relationship})`)}a.meta?.eventStream&&(e.push(""),e.push("**Event Stream:** Yes (supports funnel, flow, retention queries)"),a.meta.eventStream.bindingKey&&e.push(`- Binding key: \`${a.name}.${a.meta.eventStream.bindingKey}\``),a.meta.eventStream.timeDimension&&e.push(`- Time dimension: \`${a.name}.${a.meta.eventStream.timeDimension}\``)),e.push("")}return e.join(`
2
+ `)}function F(o){return o.messages.map(e=>e.content.text).join(`
3
+
4
+ `)}function j(o){return["# Drizzle Cube Analytics Agent","","You are an analytics agent that helps users explore and visualize data.","You have access to a semantic layer with cubes (data models) that you can query.","","## Your Workflow","","1. **Discover** available cubes using `discover_cubes` to understand the data","2. **Explain your approach** by calling `add_markdown` to describe what you plan to analyze and why","3. **Query** data using `execute_query` with properly structured queries","4. **Explain results** by calling `add_markdown` to describe what the data shows, key insights, and methodology","5. **Visualize** results by calling `add_portlet` to add charts/tables to the notebook","","## Important Guidelines","","- ALWAYS discover cubes first before attempting queries","- Use `add_portlet` to create visualizations after getting query results","- Use `add_markdown` to explain your findings, methodology, and insights","- Choose appropriate chart types: bar for categories, line for trends, table for detailed data","- When showing data, always add both a portlet (visualization) and markdown (explanation)","- If a query fails, explain the error and try an alternative approach","","## Output Format Rules","","### CRITICAL: Always think before acting","- EVERY single turn MUST begin with a text message (1-2 sentences) BEFORE any tool calls. This is your #1 rule — never violate it.","- This applies to EVERY turn, including turns where you are adding visualizations or explanations to the notebook.",`- 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."`,'- Example good turn: "Let me discover what data is available." → discover_cubes',`- Example good turn: "I'll add a bar chart showing the top employees." → add_markdown → add_portlet`,"- Example bad turn: (no text) → add_portlet ← NEVER do this","","### Text vs Notebook","- ALL analysis, findings, methodology, and insights MUST go through `add_markdown` tool calls — never in your text responses","- Your text responses must be 1-2 short sentences (under 50 words) summarizing what you are about to do next — status updates only","- Never use markdown formatting (headers, bullets, bold, code blocks) in text responses — plain sentences only","","### Notebook content rules","- Before each `add_portlet`, ALWAYS call `add_markdown` first to explain WHY you are adding this visualization and what it shows","- Before calling `add_portlet`, verify the query is valid: all fields in `order` must also appear in `measures` or `dimensions`",'- Never put data tables in markdown blocks — use `add_portlet` with chartType "table" instead',"- Think out loud in the notebook: use `add_markdown` to share your reasoning at each step so users can follow along","","## Chart Selection Guide","","Choose chart types based on the user's intent and data shape:","","| Intent / Data Shape | Chart Type |","|---|---|","| Single headline metric (total revenue, user count) | `kpiNumber` |","| Headline metric with period-over-period change | `kpiDelta` |","| Compare discrete categories or rankings | `bar` |","| Trend over time (one or few series) | `line` |","| Trend over time showing volume/magnitude | `area` |","| Part-of-whole breakdown | `pie` (≤7 slices) |","| Correlation between two measures | `scatter` |","| Correlation with size/color third dimension | `bubble` |","| Intensity across two categorical dimensions | `heatmap` |","| Multi-variable comparison across categories | `radar` |","| Distribution/spread of values | `boxPlot` |","| Detailed row-level data or many columns | `table` |","","Analysis-mode-specific chart types (require the corresponding analysis mode):","","| Analysis Mode | Chart Type | Description |","|---|---|---|","| Funnel | `funnel` | Sequential step conversion bars with conversion rates |","| Flow | `sankey` | Flow diagram showing paths between states/steps |","| Flow | `sunburst` | Radial rings showing forward paths from a starting event |","| Retention | `retentionHeatmap` | Cohort × period retention matrix |","| Retention | `retentionCombined` | Retention with line chart, heatmap, or combined modes |","","Defaults: If unsure, use `bar` for categories, `line` for time series, `table` for exploratory data.","","## Analysis Mode Decision Tree","","The default mode is **query** (standard measures/dimensions). Switch to a special mode only when the user's question matches:","",'- **Funnel mode** — "What is the conversion rate from step A → B → C?" or "How many users complete signup?"'," - Requires: an event-stream cube with `capabilities.funnel = true` from `discover_cubes`",' - Query format: `{ queryType: "funnel", bindingKey, timeDimension, steps: [...] }`'," - Chart type: `funnel`","",'- **Flow mode** — "What paths do users take after signup?" or "Show me the most common navigation flows"'," - Requires: `capabilities.flow = true` from `discover_cubes`",' - Query format: `{ queryType: "flow", bindingKey, timeDimension, startStep, maxSteps }`'," - Chart types: `sankey` (flow diagram) or `sunburst` (radial paths)","",'- **Retention mode** — "What % of users come back after 7 days?" or "Show me weekly retention cohorts"'," - Requires: `capabilities.retention = true` from `discover_cubes`",' - Query format: `{ queryType: "retention", bindingKey, timeDimension, retentionStep, ... }`'," - Chart types: `retentionHeatmap` (cohort matrix) or `retentionCombined` (line + heatmap)","","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.","","Event-stream cubes are marked in the Available Cubes section below with **Event Stream: Yes** and list their binding key and time dimension.","","---","",F(S.MCP_GUIDE_PROMPT),"","---","",F(S.QUERY_RULES_PROMPT),"","---","",F(S.QUERY_BUILDING_PROMPT),"","---","",F(S.DATE_FILTERING_PROMPT),"","---","",B(o)].join(`
5
+ `)}const G={label:"Bar Chart",description:"Compare values across categories",useCase:"Best for comparing discrete categories, showing rankings, or displaying changes over time",clickableElements:{bar:!0},dropZones:[{key:"xAxis",label:"X-Axis (Categories)",description:"Dimensions and time dimensions for grouping",mandatory:!1,acceptTypes:["dimension","timeDimension"],emptyText:"Drop dimensions & time dimensions here"},{key:"yAxis",label:"Y-Axis (Values)",description:"Measures for bar heights",mandatory:!0,acceptTypes:["measure"],emptyText:"Drop measures here",enableDualAxis:!0},{key:"series",label:"Series (Split into Multiple Series)",description:"Dimensions to create separate data series",mandatory:!1,acceptTypes:["dimension"],emptyText:"Drop dimensions here to split data into series"}],displayOptions:["showLegend","showGrid","showTooltip","hideHeader"],displayOptionsConfig:[{key:"stackType",label:"Stacking",type:"select",defaultValue:"none",options:[{value:"none",label:"None"},{value:"normal",label:"Stacked"},{value:"percent",label:"Stacked 100%"}],description:"How to stack multiple bar series"},{key:"target",label:"Target Values",type:"string",placeholder:"e.g., 100 or 50,75 for spread",description:"Single value or comma-separated values to spread across X-axis"},{key:"leftYAxisFormat",label:"Left Y-Axis Format",type:"axisFormat",description:"Number formatting for left Y-axis"},{key:"rightYAxisFormat",label:"Right Y-Axis Format",type:"axisFormat",description:"Number formatting for right Y-axis"}]},Z={label:"Line Chart",description:"Show trends and changes over time",useCase:"Best for continuous data, trends, time series, and showing relationships between multiple series",clickableElements:{point:!0},dropZones:[{key:"xAxis",label:"X-Axis (Time/Categories)",description:"Time dimensions or dimensions for X-axis",mandatory:!0,acceptTypes:["dimension","timeDimension"],emptyText:"Drop time dimensions or dimensions here"},{key:"yAxis",label:"Y-Axis (Values)",description:"Measures for line values",mandatory:!0,acceptTypes:["measure"],emptyText:"Drop measures here",enableDualAxis:!0},{key:"series",label:"Series (Multiple Lines)",description:"Dimensions to create separate lines",mandatory:!1,acceptTypes:["dimension"],emptyText:"Drop dimensions here for multiple lines"}],displayOptions:["showLegend","showGrid","showTooltip","hideHeader"],displayOptionsConfig:[{key:"connectNulls",label:"Connect Nulls",type:"boolean",defaultValue:!1,description:"Draw continuous line through missing data points"},{key:"target",label:"Target Values",type:"string",placeholder:"e.g., 100 or 50,75 for spread",description:"Single value or comma-separated values to spread across X-axis"},{key:"priorPeriodStyle",label:"Prior Period Line Style",type:"select",defaultValue:"dashed",options:[{value:"dashed",label:"Dashed"},{value:"dotted",label:"Dotted"},{value:"solid",label:"Solid"}],description:"Line style for prior period in comparison mode"},{key:"priorPeriodOpacity",label:"Prior Period Opacity",type:"number",defaultValue:.5,min:.1,max:1,step:.1,description:"Opacity for prior period lines (0.1 to 1)"},{key:"leftYAxisFormat",label:"Left Y-Axis Format",type:"axisFormat",description:"Number formatting for left Y-axis"},{key:"rightYAxisFormat",label:"Right Y-Axis Format",type:"axisFormat",description:"Number formatting for right Y-axis"}]},X={label:"Area Chart",description:"Emphasize magnitude of change over time",useCase:"Best for showing cumulative totals, volume changes, or stacked comparisons over time",dropZones:[{key:"xAxis",label:"X-Axis (Time/Categories)",description:"Time dimensions or dimensions for X-axis",mandatory:!0,acceptTypes:["dimension","timeDimension"],emptyText:"Drop time dimensions or dimensions here"},{key:"yAxis",label:"Y-Axis (Values)",description:"Measures for area values",mandatory:!0,acceptTypes:["measure"],emptyText:"Drop measures here",enableDualAxis:!0},{key:"series",label:"Series (Stack Areas)",description:"Dimensions to create stacked areas",mandatory:!1,acceptTypes:["dimension"],emptyText:"Drop dimensions here for stacked areas"}],displayOptions:["showLegend","showGrid","showTooltip","hideHeader"],displayOptionsConfig:[{key:"stackType",label:"Stacking",type:"select",defaultValue:"none",options:[{value:"none",label:"None"},{value:"normal",label:"Stacked"},{value:"percent",label:"Stacked 100%"}],description:"How to stack multiple area series"},{key:"connectNulls",label:"Connect Nulls",type:"boolean",defaultValue:!1,description:"Draw continuous line through missing data points"},{key:"target",label:"Target Values",type:"string",placeholder:"e.g., 100 or 50,75 for spread",description:"Single value or comma-separated values to spread across X-axis"},{key:"leftYAxisFormat",label:"Left Y-Axis Format",type:"axisFormat",description:"Number formatting for left Y-axis"},{key:"rightYAxisFormat",label:"Right Y-Axis Format",type:"axisFormat",description:"Number formatting for right Y-axis"}]},U={label:"Pie Chart",description:"Show proportions of a whole",useCase:"Best for showing percentage distribution or composition of a total (limit to 5-7 slices)",clickableElements:{slice:!0},dropZones:[{key:"xAxis",label:"Categories",description:"Dimension for pie slices",mandatory:!0,maxItems:1,acceptTypes:["dimension"],emptyText:"Drop a dimension for categories"},{key:"yAxis",label:"Values",description:"Measure for slice sizes",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure for values"}],displayOptions:["showLegend","showTooltip","hideHeader"],displayOptionsConfig:[{key:"leftYAxisFormat",label:"Value Format",type:"axisFormat",description:"Number formatting for values"}]},K={label:"Scatter Plot",description:"Reveal correlations between variables",useCase:"Best for identifying patterns, correlations, outliers, and relationships between two measures",dropZones:[{key:"xAxis",label:"X-Axis",description:"Measure or dimension for X position",mandatory:!0,maxItems:1,acceptTypes:["dimension","timeDimension","measure"],emptyText:"Drop a field for X-axis"},{key:"yAxis",label:"Y-Axis",description:"Measure for Y position",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure for Y-axis"},{key:"series",label:"Series (Color Groups)",description:"Dimension to color points by category",mandatory:!1,maxItems:1,acceptTypes:["dimension"],emptyText:"Drop a dimension to color points"}],displayOptions:["showLegend","showGrid","showTooltip","hideHeader"],displayOptionsConfig:[{key:"xAxisFormat",label:"X-Axis Format",type:"axisFormat",description:"Number formatting for X-axis"},{key:"leftYAxisFormat",label:"Y-Axis Format",type:"axisFormat",description:"Number formatting for Y-axis"}]},Q={label:"Bubble Chart",description:"Compare three dimensions of data",useCase:"Best for showing relationships between three variables (X, Y, and size), market analysis",dropZones:[{key:"xAxis",label:"X-Axis",description:"Horizontal axis position",mandatory:!0,maxItems:1,acceptTypes:["dimension","timeDimension","measure"],emptyText:"Drop a field for X-axis position"},{key:"yAxis",label:"Y-Axis",description:"Vertical axis position",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure for Y-axis position"},{key:"sizeField",label:"Bubble Radius",description:"Size of bubbles based on this measure",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure for bubble size"},{key:"series",label:"Bubble Labels",description:"Field to use for bubble labels and identification",mandatory:!0,maxItems:1,acceptTypes:["dimension"],emptyText:"Drop a dimension for bubble labels"},{key:"colorField",label:"Bubble Colour",description:"Color bubbles by this field (optional)",mandatory:!1,maxItems:1,acceptTypes:["dimension","measure"],emptyText:"Drop a field for bubble color (optional)"}],displayOptions:["showLegend","showGrid","showTooltip","minBubbleSize","maxBubbleSize","bubbleOpacity","hideHeader"],displayOptionsConfig:[{key:"xAxisFormat",label:"X-Axis Format",type:"axisFormat",description:"Number formatting for X-axis"},{key:"leftYAxisFormat",label:"Y-Axis Format",type:"axisFormat",description:"Number formatting for Y-axis and values"}]},W={label:"Radar Chart",description:"Compare multiple metrics across categories",useCase:"Best for multivariate comparisons, performance metrics, strengths/weaknesses analysis",dropZones:[{key:"xAxis",label:"Axes (Categories)",description:"Dimensions for radar axes",mandatory:!0,acceptTypes:["dimension"],emptyText:"Drop dimensions for radar axes"},{key:"yAxis",label:"Values",description:"Measures for radar values",mandatory:!0,acceptTypes:["measure"],emptyText:"Drop measures for values"},{key:"series",label:"Series (Multiple Shapes)",description:"Dimensions to create multiple radar shapes",mandatory:!1,acceptTypes:["dimension"],emptyText:"Drop dimensions for multiple shapes"}],displayOptions:["showLegend","showGrid","showTooltip","hideHeader"],displayOptionsConfig:[{key:"leftYAxisFormat",label:"Value Format",type:"axisFormat",description:"Number formatting for values"}]},J={label:"Radial Bar Chart",description:"Circular progress and KPI visualization",useCase:"Best for showing progress toward goals, KPIs, or comparing percentages in a compact form",dropZones:[{key:"xAxis",label:"Categories",description:"Dimensions for radial segments",mandatory:!0,acceptTypes:["dimension"],emptyText:"Drop dimensions for categories"},{key:"yAxis",label:"Values",description:"Measures for radial bar lengths",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure for values"}],displayOptions:["showLegend","showTooltip","hideHeader"],displayOptionsConfig:[{key:"leftYAxisFormat",label:"Value Format",type:"axisFormat",description:"Number formatting for values"}]},ee={label:"TreeMap",description:"Visualize hierarchical data with nested rectangles",useCase:"Best for showing part-to-whole relationships in hierarchical data, disk usage, budget allocation",dropZones:[{key:"xAxis",label:"Categories",description:"Dimensions for treemap rectangles",mandatory:!0,acceptTypes:["dimension"],emptyText:"Drop dimensions for categories"},{key:"yAxis",label:"Size",description:"Measure for rectangle sizes",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure for size"},{key:"series",label:"Color Groups",description:"Dimension to color rectangles by category",mandatory:!1,maxItems:1,acceptTypes:["dimension"],emptyText:"Drop a dimension for color grouping"}],displayOptions:["showLegend","showTooltip","hideHeader"],displayOptionsConfig:[{key:"leftYAxisFormat",label:"Value Format",type:"axisFormat",description:"Number formatting for size values"}],clickableElements:{cell:!0}},te={label:"Data Table",description:"Display detailed tabular data",useCase:"Best for precise values, detailed analysis, sortable/filterable data exploration",dropZones:[{key:"xAxis",label:"Columns",description:"All fields to display as columns",mandatory:!1,acceptTypes:["dimension","timeDimension","measure"],emptyText:"Drop fields to display as columns (or leave empty for all)"}],displayOptions:["hideHeader"],displayOptionsConfig:[{key:"leftYAxisFormat",label:"Value Format",type:"axisFormat",description:"Number formatting for numeric values"}]},ae={label:"Activity Grid",description:"GitHub-style activity grid showing temporal patterns across different time scales",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",dropZones:[{key:"dateField",label:"Time Dimension",description:"Time field that determines grid structure (granularity affects layout)",mandatory:!0,maxItems:1,acceptTypes:["timeDimension"],emptyText:"Drop a time dimension (granularity affects grid structure)"},{key:"valueField",label:"Activity Measure",description:"Measure used for activity intensity (color coding)",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure for activity intensity"}],displayOptions:["showLabels","showTooltip","hideHeader"],displayOptionsConfig:[{key:"fitToWidth",label:"Fit to Width",type:"boolean",defaultValue:!1,description:"Automatically size blocks to fill portlet width and height while maintaining aspect ratio"}],validate:o=>{const{dateField:e,valueField:a}=o;return!e||Array.isArray(e)&&e.length===0?{isValid:!1,message:"Time dimension is required for activity grid"}:!a||Array.isArray(a)&&a.length===0?{isValid:!1,message:"Activity measure is required for intensity mapping"}:{isValid:!0}},clickableElements:{cell:!0}},ie={label:"KPI Number",description:"Display key performance indicators as large numbers",useCase:"Perfect for showing important metrics like revenue, user count, or other key business metrics in a prominent, easy-to-read format",dropZones:[{key:"yAxis",label:"Value",description:"Measure to display as KPI number",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure here"}],displayOptionsConfig:[{key:"target",label:"Target Value",type:"string",placeholder:"e.g., 100",description:"Target value to compare against (first value used if multiple provided)"},{key:"prefix",label:"Prefix",type:"string",placeholder:"e.g., $, €, #",description:"Text to display before the number"},{key:"suffix",label:"Suffix",type:"string",placeholder:"e.g., %, units, items",description:"Text to display after the number"},{key:"decimals",label:"Decimal Places",type:"number",defaultValue:0,min:0,max:10,step:1,description:"Number of decimal places to display"},{key:"valueColorIndex",label:"Value Color",type:"paletteColor",defaultValue:0,description:"Color from the dashboard palette for the KPI value text"},{key:"useLastCompletePeriod",label:"Use Last Complete Period",type:"boolean",defaultValue:!0,description:"Exclude current incomplete period from aggregation (e.g., partial week/month)"},{key:"skipLastPeriod",label:"Skip Last Period",type:"boolean",defaultValue:!1,description:"Always exclude the last period regardless of completeness"}],displayOptions:["hideHeader"]},oe={label:"KPI Delta",description:"Display change between latest and previous values with trend indicators",useCase:"Perfect for showing performance changes over time, such as revenue growth, user acquisition changes, or other metrics where the trend and delta are more important than the absolute value",dropZones:[{key:"yAxis",label:"Value",description:"Measure to track changes for",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure here"},{key:"xAxis",label:"Dimension (optional)",description:"Dimension for ordering data (typically time)",mandatory:!1,maxItems:1,acceptTypes:["dimension","timeDimension"],emptyText:"Drop a dimension for ordering"}],displayOptionsConfig:[{key:"prefix",label:"Prefix",type:"string",placeholder:"e.g., $, €, #",description:"Text to display before the number"},{key:"suffix",label:"Suffix",type:"string",placeholder:"e.g., %, units, items",description:"Text to display after the number"},{key:"decimals",label:"Decimal Places",type:"number",defaultValue:1,min:0,max:10,step:1,description:"Number of decimal places to display"},{key:"positiveColorIndex",label:"Positive Change Color",type:"paletteColor",defaultValue:2,description:"Color for positive changes (increases)"},{key:"negativeColorIndex",label:"Negative Change Color",type:"paletteColor",defaultValue:3,description:"Color for negative changes (decreases)"},{key:"showHistogram",label:"Show Variance Histogram",type:"boolean",defaultValue:!0,description:"Display historical variance chart below the delta"},{key:"useLastCompletePeriod",label:"Use Last Complete Period",type:"boolean",defaultValue:!0,description:"Exclude current incomplete period from delta calculation (e.g., partial week/month)"},{key:"skipLastPeriod",label:"Skip Last Period",type:"boolean",defaultValue:!1,description:"Always exclude the last period regardless of completeness"}],displayOptions:["hideHeader"],validate:o=>!o.yAxis||Array.isArray(o.yAxis)&&o.yAxis.length===0?{isValid:!1,message:"A measure is required for KPI Delta charts"}:{isValid:!0}},se={label:"KPI Text",description:"Display key performance indicators as customizable text",useCase:"Perfect for showing metrics with custom formatting, combining multiple values, or displaying contextual KPI information using templates",dropZones:[{key:"yAxis",label:"Value",description:"Measure to display in the KPI text template",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop a measure here"}],displayOptionsConfig:[{key:"template",label:"Text Template",type:"string",placeholder:"e.g., Total Revenue: ${value}",description:"Template for displaying the text. Use ${value} to insert the measure value."},{key:"decimals",label:"Decimal Places",type:"number",defaultValue:0,min:0,max:10,step:1,description:"Number of decimal places to display for numeric values"},{key:"valueColorIndex",label:"Value Color",type:"paletteColor",defaultValue:0,description:"Color from the dashboard palette for the KPI value text"}],displayOptions:["hideHeader"]},re={label:"Markdown",description:"Display custom markdown content with formatting",useCase:"Perfect for adding documentation, notes, section headers, instructions, or formatted text to dashboards",skipQuery:!0,dropZones:[],displayOptionsConfig:[{key:"content",label:"Markdown Content",type:"string",placeholder:`# Welcome
6
+
7
+ Add your **markdown** content here:
8
+
9
+ - Lists with bullets
10
+ - [Links](https://example.com)
11
+ - *Italic* and **bold** text
12
+
13
+ ---
14
+
15
+ Use --- for horizontal rules.`,description:"Enter markdown text. Supports headers (#), bold (**text**), italic (*text*), links ([text](url)), lists (- item), and horizontal rules (---)."},{key:"accentColorIndex",label:"Accent Color",type:"paletteColor",defaultValue:0,description:"Color from the dashboard palette for headers, bullets, and links"},{key:"fontSize",label:"Font Size",type:"select",defaultValue:"medium",options:[{value:"small",label:"Small"},{value:"medium",label:"Medium"},{value:"large",label:"Large"}],description:"Overall text size for the markdown content"},{key:"alignment",label:"Text Alignment",type:"select",defaultValue:"left",options:[{value:"left",label:"Left"},{value:"center",label:"Center"},{value:"right",label:"Right"}],description:"Horizontal alignment of the markdown content"},{key:"hideHeader",label:"Hide Header",type:"boolean",defaultValue:!0,description:"Hide the portlet header bar (title and action buttons)"},{key:"transparentBackground",label:"Transparent Background",type:"boolean",defaultValue:!1,description:"Remove card background, border, and shadow for seamless integration as section headers"},{key:"autoHeight",label:"Auto Height",type:"boolean",defaultValue:!0,description:"In row and mobile layouts, size to markdown content instead of fixed row height"},{key:"accentBorder",label:"Accent Border",type:"select",defaultValue:"none",options:[{value:"none",label:"None"},{value:"left",label:"Left"},{value:"top",label:"Top"},{value:"bottom",label:"Bottom"}],description:"Add an accent-colored border on one side of the content"}]},ne={label:"Funnel Chart",description:"Show conversion through sequential steps",useCase:"Best for visualizing user journey funnels, sales pipelines, or multi-step processes",dropZones:[{key:"xAxis",label:"Step Name",description:"Step names (auto-populated from funnel steps)",mandatory:!1,maxItems:1,acceptTypes:["dimension"],emptyText:"Steps defined in funnel config"},{key:"yAxis",label:"Step Count",description:"Count at each step (auto-calculated)",mandatory:!1,maxItems:1,acceptTypes:["measure"],emptyText:"Counts calculated from funnel execution"}],displayOptions:["hideHeader"],displayOptionsConfig:[{key:"funnelStyle",label:"Funnel Style",type:"buttonGroup",defaultValue:"bars",options:[{value:"bars",label:"Bars"},{value:"funnel",label:"Funnel"}],description:"Visualization style"},{key:"funnelOrientation",label:"Orientation",type:"buttonGroup",defaultValue:"horizontal",options:[{value:"horizontal",label:"Horizontal"},{value:"vertical",label:"Vertical"}]},{key:"hideSummaryFooter",label:"Hide Summary Footer",type:"boolean",defaultValue:!1,description:"Hide the summary footer showing steps count and overall conversion"},{key:"showFunnelConversion",label:"Show Conversion Rate",type:"boolean",defaultValue:!0,description:"Display step-to-step conversion percentage"},{key:"showFunnelAvgTime",label:"Show Avg Time",type:"boolean",defaultValue:!1,description:"Display average time to convert"},{key:"showFunnelMedianTime",label:"Show Median Time",type:"boolean",defaultValue:!1,description:"Display median time to convert"},{key:"showFunnelP90Time",label:"Show P90 Time",type:"boolean",defaultValue:!1,description:"Display 90th percentile time to convert"}]},le={label:"Sankey Chart",description:"Show flow between states or steps",useCase:"Best for visualizing user journey flows, path analysis, or state transitions",dropZones:[{key:"xAxis",label:"Event Type",description:"Event dimension that categorizes flow nodes",mandatory:!1,maxItems:1,acceptTypes:["dimension"],emptyText:"Auto-populated from flow config"},{key:"yAxis",label:"Flow Count",description:"Count of entities following each path",mandatory:!1,maxItems:1,acceptTypes:["measure"],emptyText:"Calculated from flow execution"}],displayOptions:["hideHeader"],displayOptionsConfig:[{key:"linkOpacity",label:"Link Opacity",type:"buttonGroup",defaultValue:"0.5",options:[{value:"0.3",label:"Light"},{value:"0.5",label:"Medium"},{value:"0.7",label:"Dark"}],description:"Opacity of flow links"},{key:"showNodeLabels",label:"Show Node Labels",type:"boolean",defaultValue:!0,description:"Display labels on flow nodes"},{key:"hideSummaryFooter",label:"Hide Summary Footer",type:"boolean",defaultValue:!0,description:"Hide the statistics footer below the chart"}]},de={label:"Sunburst Chart",description:"Show hierarchical flow as radial rings",useCase:"Best for visualizing forward paths from a starting event in a compact radial layout",dropZones:[{key:"xAxis",label:"Event Type",description:"Event dimension that categorizes flow nodes",mandatory:!1,maxItems:1,acceptTypes:["dimension"],emptyText:"Auto-populated from flow config"},{key:"yAxis",label:"Flow Count",description:"Count of entities following each path",mandatory:!1,maxItems:1,acceptTypes:["measure"],emptyText:"Calculated from flow execution"}],displayOptions:["hideHeader"],displayOptionsConfig:[{key:"innerRadius",label:"Inner Radius",type:"number",defaultValue:40,min:0,max:100,step:10,description:"Size of the center hole (0 for full circle)"},{key:"hideSummaryFooter",label:"Hide Summary Footer",type:"boolean",defaultValue:!0,description:"Hide the statistics footer below the chart"}]},pe={label:"Heatmap",description:"Visualize intensity across two dimensions",useCase:"Best for showing patterns in matrix data like correlations, schedules, or category comparisons",dropZones:[{key:"xAxis",label:"Columns (X-Axis)",description:"Dimension for column categories",mandatory:!0,maxItems:1,acceptTypes:["dimension"],emptyText:"Drop one dimension here"},{key:"yAxis",label:"Rows (Y-Axis)",description:"Dimension for row categories",mandatory:!0,maxItems:1,acceptTypes:["dimension"],emptyText:"Drop one dimension here"},{key:"valueField",label:"Value (Color Intensity)",description:"Measure that determines cell color",mandatory:!0,maxItems:1,acceptTypes:["measure"],emptyText:"Drop one measure here"}],displayOptions:["showLegend","showTooltip"],displayOptionsConfig:[{key:"showLabels",label:"Show Cell Values",type:"boolean",defaultValue:!1,description:"Display values inside each cell"},{key:"cellShape",label:"Cell Shape",type:"select",defaultValue:"rect",options:[{value:"rect",label:"Rectangle"},{value:"circle",label:"Circle"}]},{key:"xAxisFormat",label:"X-Axis Format",type:"axisFormat",description:"Number formatting for X-axis labels"},{key:"yAxisFormat",label:"Y-Axis Format",type:"axisFormat",description:"Number formatting for Y-axis labels"},{key:"valueFormat",label:"Value Format",type:"axisFormat",description:"Number formatting for cell values and legend"}],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"}},ue={label:"Retention Matrix",dropZones:[],displayOptionsConfig:[{key:"showLegend",label:"Show Legend",type:"boolean",defaultValue:!0,description:"Show the color intensity legend"},{key:"showTooltip",label:"Show Tooltip",type:"boolean",defaultValue:!0,description:"Show tooltip on hover with detailed stats"}],description:"Cohort retention matrix visualization",useCase:"Visualize user retention over time by cohort"},ce={label:"Retention Chart",dropZones:[],displayOptionsConfig:[{key:"retentionDisplayMode",label:"Display Mode",type:"select",defaultValue:"line",options:[{value:"line",label:"Line Chart"},{value:"heatmap",label:"Heatmap Table"},{value:"combined",label:"Combined"}],description:"Choose how to visualize retention data"},{key:"showLegend",label:"Show Legend",type:"boolean",defaultValue:!0,description:"Show the legend for breakdown segments"},{key:"showGrid",label:"Show Grid",type:"boolean",defaultValue:!0,description:"Show grid lines on the chart"},{key:"showTooltip",label:"Show Tooltip",type:"boolean",defaultValue:!0,description:"Show tooltip on hover with detailed stats"}],description:"Combined retention visualization with line chart and heatmap modes",useCase:"Visualize user retention over time with optional breakdown segmentation"},me={label:"Box Plot",description:"Show statistical distribution (median, IQR, whiskers) across categories",useCase:"Best for P&L spread per symbol, trade size distribution, latency distribution across platforms",dropZones:[{key:"xAxis",label:"X-Axis (Groups)",description:"Dimension to group boxes by (e.g. symbol, platform)",mandatory:!0,maxItems:1,acceptTypes:["dimension","timeDimension"],emptyText:"Drop a dimension here"},{key:"yAxis",label:"Y-Axis (Measures)",description:"For auto mode: drop 1 measure here. For 3-measure mode set avg/stddev/median fields in Display Options.",mandatory:!1,acceptTypes:["measure"],emptyText:"Drop a measure here (or configure 3/5-measure mode below)"}],displayOptionsConfig:[{key:"avgField",label:"Avg Field (3-measure mode)",type:"string",placeholder:"e.g. Trades.avgPnl",description:"Average measure for 3-measure mode (mean ± σ whiskers)"},{key:"stddevField",label:"Stddev Field (3-measure mode)",type:"string",placeholder:"e.g. Trades.stddevPnl",description:"Standard deviation measure for 3-measure mode"},{key:"medianField",label:"Median Field (3/5-measure mode)",type:"string",placeholder:"e.g. Trades.medianPnl",description:"Median measure for 3-measure or 5-measure mode"},{key:"minField",label:"Min Field (5-measure mode)",type:"string",placeholder:"e.g. Trades.minPnl",description:"Minimum measure for 5-measure full box plot"},{key:"q1Field",label:"Q1 Field (5-measure mode)",type:"string",placeholder:"e.g. Trades.q1Pnl",description:"First quartile measure for 5-measure full box plot"},{key:"q3Field",label:"Q3 Field (5-measure mode)",type:"string",placeholder:"e.g. Trades.q3Pnl",description:"Third quartile measure for 5-measure full box plot"},{key:"maxField",label:"Max Field (5-measure mode)",type:"string",placeholder:"e.g. Trades.maxPnl",description:"Maximum measure for 5-measure full box plot"},{key:"leftYAxisFormat",label:"Y-Axis Format",type:"axisFormat",description:"Number formatting for the value axis"}]},_={bar:G,line:Z,area:X,pie:U,scatter:K,bubble:Q,radar:W,radialBar:J,treemap:ee,table:te,activityGrid:ae,kpiNumber:ie,kpiDelta:oe,kpiText:se,markdown:re,funnel:ne,sankey:le,sunburst:de,heatmap:pe,retentionHeatmap:ue,retentionCombined:ce,boxPlot:me};function ye(o,e,a){const i=_[o];if(!i)return{isValid:!0,errors:[]};if(i.skipQuery)return{isValid:!0,errors:[]};const t=[];for(const r of i.dropZones){if(!r.mandatory)continue;const n=e?.[r.key];if(!(Array.isArray(n)?n.length>0:!!n)){const c=r.acceptTypes?.join("/")??"fields";t.push(`chartConfig.${r.key} is required for ${o} chart (${r.label}). Accepts: ${c}.`)}}return{isValid:t.length===0,errors:t}}function fe(o,e,a){const i=_[o];if(!i)return e??{};const t={...e},r=a.measures??[],n=a.dimensions??[],c=(a.timeDimensions??[]).map(l=>l.dimension);for(const l of i.dropZones){const d=t[l.key];if(Array.isArray(d)?d.length>0:!!d)continue;const y=l.acceptTypes??[];if(l.key==="sizeField"||l.key==="colorField"){if(y.includes("measure")){const x=new Set;for(const k of i.dropZones){if(k.key===l.key)continue;const m=t[k.key];Array.isArray(m)?m.forEach(v=>x.add(v)):typeof m=="string"&&x.add(m)}const u=r.filter(k=>!x.has(k));u.length>0&&(t[l.key]=u[0])}continue}const g=[];if(y.includes("dimension")&&g.push(...n),y.includes("timeDimension")&&g.push(...c),y.includes("measure")&&g.push(...r),g.length===0)continue;const V=l.maxItems??1/0,A=g.slice(0,V);A.length>0&&(t[l.key]=A)}return t}function he(o){const e=[`
16
+ Chart config requirements by type:`];for(const a of o){const i=_[a];if(!i)continue;const t=i.description??"",r=i.useCase??"",n=[t,r].filter(Boolean).join(". "),p=n?` — ${n}.`:"",c=i.dropZones.filter(d=>d.mandatory);if(c.length===0&&!i.skipQuery){e.push(` ${a}${p} chartConfig auto-inferred from query.`);continue}if(i.skipQuery){e.push(` ${a}${p} No query needed.`);continue}const l=c.map(d=>{const b=d.acceptTypes?.join("/")??"any",y=d.maxItems?` (max ${d.maxItems})`:"";return`${d.key}=[${b}]${y}`});e.push(` ${a}${p} Requires ${l.join(", ")}.`)}return e.join(`
17
+ `)}const z=["bar","line","area","pie","scatter","radar","bubble","table","kpiNumber","kpiDelta","funnel","heatmap","sankey","sunburst","retentionHeatmap","retentionCombined","boxPlot"];function be(){return[{name:"discover_cubes",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.",input_schema:{type:"object",properties:{topic:{type:"string",description:'Keyword to search (e.g., "sales", "employees")'},intent:{type:"string",description:'Natural language goal (e.g., "analyze productivity trends")'},limit:{type:"number",description:"Max results (default: 10)"},minScore:{type:"number",description:"Min relevance 0-1 (default: 0.1)"}}}},{name:"get_cube_metadata",description:"Get full metadata for all registered cubes including all measures, dimensions, types, and relationships. Use this for detailed schema information.",input_schema:{type:"object",properties:{}}},{name:"execute_query",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.",input_schema:{type:"object",properties:{measures:{type:"array",items:{type:"string"},description:'Aggregation measures (e.g., ["Employees.count"])'},dimensions:{type:"array",items:{type:"string"},description:'Grouping dimensions (e.g., ["Employees.name"])'},filters:{type:"array",items:{type:"object",properties:{member:{type:"string"},operator:{type:"string"},values:{type:"array",items:{}}},required:["member","operator"]},description:"Filter conditions"},timeDimensions:{type:"array",items:{type:"object",properties:{dimension:{type:"string"},granularity:{type:"string"},dateRange:{}},required:["dimension"]},description:"Time dimensions with optional granularity"},order:{type:"object",description:'Sort order (e.g., {"Employees.count": "desc"})'},limit:{type:"number",description:"Row limit"}}}},{name:"add_portlet",description:`Add a chart visualization to the notebook.
18
+ `+he(z)+`
19
+ The query is validated before adding. The portlet fetches its own data.`,input_schema:{type:"object",properties:{title:{type:"string",description:"Title for the visualization"},query:{type:"string",description:"JSON string of the CubeQuery to visualize"},chartType:{type:"string",enum:z,description:"Chart type to render"},chartConfig:{type:"object",properties:{xAxis:{type:"array",items:{type:"string"}},yAxis:{type:"array",items:{type:"string"}},series:{type:"array",items:{type:"string"}},sizeField:{type:"string"},colorField:{type:"string"}},description:"Chart axis configuration"},displayConfig:{type:"object",properties:{showLegend:{type:"boolean"},showGrid:{type:"boolean"},showTooltip:{type:"boolean"},stacked:{type:"boolean"},orientation:{type:"string",enum:["horizontal","vertical"]}},description:"Chart display configuration"}},required:["title","query","chartType"]}},{name:"add_markdown",description:"Add an explanation or analysis text block to the notebook. Use markdown formatting. Use this to explain findings, methodology, and insights alongside visualizations.",input_schema:{type:"object",properties:{title:{type:"string",description:"Optional title for the text block"},content:{type:"string",description:"Markdown content to display"}},required:["content"]}}]}function ge(o){const{semanticLayer:e,securityContext:a}=o,i=new Map;return i.set("discover_cubes",async t=>{const r=await q.handleDiscover(e,{topic:t.topic,intent:t.intent,limit:t.limit,minScore:t.minScore});return{result:JSON.stringify(r,null,2)}}),i.set("get_cube_metadata",async()=>{const t=e.getMetadata();return{result:JSON.stringify(t,null,2)}}),i.set("execute_query",async t=>{try{const r={measures:t.measures,dimensions:t.dimensions,filters:t.filters,timeDimensions:t.timeDimensions,order:t.order,limit:t.limit},n=await q.handleLoad(e,a,{query:r});return{result:JSON.stringify({rowCount:n.data.length,data:n.data,annotation:n.annotation},null,2)}}catch(r){return{result:`Query execution failed: ${r instanceof Error?r.message:"Unknown error"}`,isError:!0}}}),i.set("add_portlet",async t=>{const n={number:"kpiNumber",retention:"retentionHeatmap"}[t.chartType]??t.chartType;let p;try{p=JSON.parse(t.query)}catch{return{result:"Invalid query: could not parse JSON string. Ensure `query` is a valid JSON string.",isError:!0}}const c=e.validateQuery(p);if(!c.isValid)return{result:`Invalid query — fix these errors and retry:
20
+ ${c.errors.join(`
21
+ `)}`,isError:!0};const l=fe(n,t.chartConfig,p),d=ye(n,l);if(!d.isValid)return{result:`Chart config invalid — fix these errors and retry:
22
+ ${d.errors.join(`
23
+ `)}`,isError:!0};const b=`portlet-${Date.now()}-${Math.random().toString(36).slice(2,7)}`,y={id:b,title:t.title,query:t.query,chartType:n,chartConfig:l,displayConfig:t.displayConfig};return{result:`Portlet "${t.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.]`,sideEffect:{type:"add_portlet",data:y}}}),i.set("add_markdown",async t=>{const r=`markdown-${Date.now()}-${Math.random().toString(36).slice(2,7)}`,n={id:r,title:t.title,content:t.content};return{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.]`,sideEffect:{type:"add_markdown",data:n}}}),i}async function*xe(o){const{message:e,sessionId:a,semanticLayer:i,securityContext:t,agentConfig:r,apiKey:n}=o;let p;try{const u=await import("@anthropic-ai/sdk");p=u.default||u.Anthropic||u}catch{yield{type:"error",data:{message:"@anthropic-ai/sdk is required. Install it with: npm install @anthropic-ai/sdk"}};return}const c=new p({apiKey:n}),l=be(),d=ge({semanticLayer:i,securityContext:t}),b=i.getMetadata(),y=j(b),g=r.model||"claude-sonnet-4-6",V=r.maxTurns||25,A=r.maxTokens||4096,x=[{role:"user",content:e}];try{for(let u=0;u<V;u++){const k=await c.messages.create({model:g,max_tokens:A,system:y,tools:l,messages:x,stream:!0}),m=[];let v=-1,C="",I="";for await(const f of k)switch(f.type){case"content_block_start":{v++;const s=f.content_block;s.type==="tool_use"?(m.push({type:"tool_use",id:s.id,name:s.name,input:{}}),C="",yield{type:"tool_use_start",data:{id:s.id,name:s.name,input:void 0}}):s.type==="text"&&m.push({type:"text",text:""});break}case"content_block_delta":{const s=f.delta;if(s.type==="text_delta"&&s.text){const T=m[v];T&&(T.text=(T.text||"")+s.text),yield{type:"text_delta",data:s.text}}else s.type==="input_json_delta"&&s.partial_json&&(C+=s.partial_json);break}case"content_block_stop":{const s=m[v];if(s?.type==="tool_use"&&C){try{s.input=JSON.parse(C)}catch{s.input={}}C=""}break}case"message_delta":{const s=f.delta;s.stop_reason&&(I=s.stop_reason);break}}if(x.push({role:"assistant",content:m}),I!=="tool_use")break;const D=[];for(const f of m){if(f.type!=="tool_use")continue;const s=f.name,T=f.input||{},w=f.id,O=d.get(s);if(!O){D.push({type:"tool_result",tool_use_id:w,content:`Unknown tool: ${s}`,is_error:!0}),yield{type:"tool_use_result",data:{id:w,name:s,result:`Unknown tool: ${s}`}};continue}try{const h=await O(T);h.sideEffect&&(yield h.sideEffect),D.push({type:"tool_result",tool_use_id:w,content:h.result,...h.isError?{is_error:!0}:{}}),yield{type:"tool_use_result",data:{id:w,name:s,result:h.result}}}catch(h){const P=h instanceof Error?h.message:"Tool execution failed";D.push({type:"tool_result",tool_use_id:w,content:P,is_error:!0}),yield{type:"tool_use_result",data:{id:w,name:s,result:P}}}}yield{type:"turn_complete",data:{}},x.push({role:"user",content:D})}yield{type:"done",data:{sessionId:a||""}}}catch(u){yield{type:"error",data:{message:u instanceof Error?u.message:"Agent execution failed"}}}}exports.handleAgentChat=xe;