@sqlrooms/deck 0.29.0-rc.11 → 0.29.0-rc.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +193 -35
  2. package/dist/BlockMapSettings.d.ts.map +1 -1
  3. package/dist/BlockMapSettings.js +4 -16
  4. package/dist/BlockMapSettings.js.map +1 -1
  5. package/dist/DashboardMapSettings.d.ts.map +1 -1
  6. package/dist/DashboardMapSettings.js +7 -10
  7. package/dist/DashboardMapSettings.js.map +1 -1
  8. package/dist/DeckJsonMap.d.ts.map +1 -1
  9. package/dist/DeckJsonMap.js +75 -23
  10. package/dist/DeckJsonMap.js.map +1 -1
  11. package/dist/DeckJsonMapSpec.d.ts +41 -0
  12. package/dist/DeckJsonMapSpec.d.ts.map +1 -1
  13. package/dist/DeckJsonMapSpec.js +2 -0
  14. package/dist/DeckJsonMapSpec.js.map +1 -1
  15. package/dist/DeckMapBasemapSelect.d.ts +9 -0
  16. package/dist/DeckMapBasemapSelect.d.ts.map +1 -0
  17. package/dist/DeckMapBasemapSelect.js +20 -0
  18. package/dist/DeckMapBasemapSelect.js.map +1 -0
  19. package/dist/DeckMapDefaultStylesProvider.d.ts +13 -19
  20. package/dist/DeckMapDefaultStylesProvider.d.ts.map +1 -1
  21. package/dist/DeckMapDefaultStylesProvider.js +11 -18
  22. package/dist/DeckMapDefaultStylesProvider.js.map +1 -1
  23. package/dist/DeckMapSurface.d.ts +1 -1
  24. package/dist/DeckMapSurface.js +1 -1
  25. package/dist/DeckMapSurface.js.map +1 -1
  26. package/dist/DeckMapsSlice.d.ts +5 -0
  27. package/dist/DeckMapsSlice.d.ts.map +1 -1
  28. package/dist/DeckMapsSlice.js +6 -3
  29. package/dist/DeckMapsSlice.js.map +1 -1
  30. package/dist/MapSettings.d.ts +14 -0
  31. package/dist/MapSettings.d.ts.map +1 -1
  32. package/dist/MapSettings.js +548 -192
  33. package/dist/MapSettings.js.map +1 -1
  34. package/dist/MapSettingsControls.d.ts +8 -1
  35. package/dist/MapSettingsControls.d.ts.map +1 -1
  36. package/dist/MapSettingsControls.js +24 -2
  37. package/dist/MapSettingsControls.js.map +1 -1
  38. package/dist/ai.d.ts.map +1 -1
  39. package/dist/ai.js +20 -12
  40. package/dist/ai.js.map +1 -1
  41. package/dist/aiNormalize.d.ts.map +1 -1
  42. package/dist/aiNormalize.js +2 -1
  43. package/dist/aiNormalize.js.map +1 -1
  44. package/dist/basemap.d.ts +23 -0
  45. package/dist/basemap.d.ts.map +1 -0
  46. package/dist/basemap.js +23 -0
  47. package/dist/basemap.js.map +1 -0
  48. package/dist/block.d.ts +1 -1
  49. package/dist/block.d.ts.map +1 -1
  50. package/dist/block.js +13 -9
  51. package/dist/block.js.map +1 -1
  52. package/dist/createOrUpdateDeckMapResource.d.ts +6 -2
  53. package/dist/createOrUpdateDeckMapResource.d.ts.map +1 -1
  54. package/dist/createOrUpdateDeckMapResource.js +57 -4
  55. package/dist/createOrUpdateDeckMapResource.js.map +1 -1
  56. package/dist/datasets/PreparedDatasetStore.d.ts +3 -4
  57. package/dist/datasets/PreparedDatasetStore.d.ts.map +1 -1
  58. package/dist/datasets/PreparedDatasetStore.js +4 -8
  59. package/dist/datasets/PreparedDatasetStore.js.map +1 -1
  60. package/dist/datasets/helpers.d.ts +39 -2
  61. package/dist/datasets/helpers.d.ts.map +1 -1
  62. package/dist/datasets/helpers.js +86 -3
  63. package/dist/datasets/helpers.js.map +1 -1
  64. package/dist/datasets/usePreparedDatasetStates.d.ts.map +1 -1
  65. package/dist/datasets/usePreparedDatasetStates.js +12 -8
  66. package/dist/datasets/usePreparedDatasetStates.js.map +1 -1
  67. package/dist/index.d.ts +6 -3
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +5 -2
  70. package/dist/index.js.map +1 -1
  71. package/dist/json/colorScaleFunction.d.ts +12 -4
  72. package/dist/json/colorScaleFunction.d.ts.map +1 -1
  73. package/dist/json/colorScaleFunction.js.map +1 -1
  74. package/dist/json/compileColorScale.d.ts +3 -2
  75. package/dist/json/compileColorScale.d.ts.map +1 -1
  76. package/dist/json/compileColorScale.js +16 -1
  77. package/dist/json/compileColorScale.js.map +1 -1
  78. package/dist/json/createDeckJsonConfiguration.d.ts.map +1 -1
  79. package/dist/json/createDeckJsonConfiguration.js +235 -175
  80. package/dist/json/createDeckJsonConfiguration.js.map +1 -1
  81. package/dist/json/defaultClasses.d.ts.map +1 -1
  82. package/dist/json/defaultClasses.js +3 -3
  83. package/dist/json/defaultClasses.js.map +1 -1
  84. package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
  85. package/dist/json/extractColorScaleLegends.js +41 -26
  86. package/dist/json/extractColorScaleLegends.js.map +1 -1
  87. package/dist/json/heatmapDefaults.d.ts +17 -7
  88. package/dist/json/heatmapDefaults.d.ts.map +1 -1
  89. package/dist/json/heatmapDefaults.js +54 -12
  90. package/dist/json/heatmapDefaults.js.map +1 -1
  91. package/dist/json/layers/DeckHeatmapLayer.d.ts +32 -0
  92. package/dist/json/layers/DeckHeatmapLayer.d.ts.map +1 -0
  93. package/dist/json/layers/DeckHeatmapLayer.js +69 -0
  94. package/dist/json/layers/DeckHeatmapLayer.js.map +1 -0
  95. package/dist/json/layers/index.d.ts +1 -0
  96. package/dist/json/layers/index.d.ts.map +1 -1
  97. package/dist/json/layers/index.js +1 -0
  98. package/dist/json/layers/index.js.map +1 -1
  99. package/dist/json/rewriteGeoArrowAccessors.d.ts.map +1 -1
  100. package/dist/json/rewriteGeoArrowAccessors.js +13 -5
  101. package/dist/json/rewriteGeoArrowAccessors.js.map +1 -1
  102. package/dist/json/scaleFunction.d.ts +5 -8
  103. package/dist/json/scaleFunction.d.ts.map +1 -1
  104. package/dist/json/scaleFunction.js +30 -5
  105. package/dist/json/scaleFunction.js.map +1 -1
  106. package/dist/mapAiConfig.d.ts +6 -0
  107. package/dist/mapAiConfig.d.ts.map +1 -1
  108. package/dist/mapAiConfig.js +7 -0
  109. package/dist/mapAiConfig.js.map +1 -1
  110. package/dist/mapAiSharedInstructions.d.ts +1 -1
  111. package/dist/mapAiSharedInstructions.d.ts.map +1 -1
  112. package/dist/mapAiSharedInstructions.js +4 -3
  113. package/dist/mapAiSharedInstructions.js.map +1 -1
  114. package/dist/mapConfig.d.ts +6 -1
  115. package/dist/mapConfig.d.ts.map +1 -1
  116. package/dist/mapConfig.js +28 -3
  117. package/dist/mapConfig.js.map +1 -1
  118. package/dist/mapConfigUtils.d.ts +22 -0
  119. package/dist/mapConfigUtils.d.ts.map +1 -1
  120. package/dist/mapConfigUtils.js +152 -5
  121. package/dist/mapConfigUtils.js.map +1 -1
  122. package/dist/mapLayerConfigUtils.d.ts +55 -0
  123. package/dist/mapLayerConfigUtils.d.ts.map +1 -1
  124. package/dist/mapLayerConfigUtils.js +222 -11
  125. package/dist/mapLayerConfigUtils.js.map +1 -1
  126. package/dist/mapResourceAuthoring.d.ts +1 -1
  127. package/dist/mapResourceAuthoring.d.ts.map +1 -1
  128. package/dist/mapResourceAuthoring.js +14 -7
  129. package/dist/mapResourceAuthoring.js.map +1 -1
  130. package/dist/mapStyles.d.ts +16 -0
  131. package/dist/mapStyles.d.ts.map +1 -0
  132. package/dist/mapStyles.js +32 -0
  133. package/dist/mapStyles.js.map +1 -0
  134. package/dist/prepare/prepareDeckDataset.d.ts.map +1 -1
  135. package/dist/prepare/prepareDeckDataset.js +1 -0
  136. package/dist/prepare/prepareDeckDataset.js.map +1 -1
  137. package/dist/prepare/types.d.ts +3 -0
  138. package/dist/prepare/types.d.ts.map +1 -1
  139. package/dist/prepare/types.js.map +1 -1
  140. package/dist/prepare/wkbDecoder.d.ts.map +1 -1
  141. package/dist/prepare/wkbDecoder.js +62 -16
  142. package/dist/prepare/wkbDecoder.js.map +1 -1
  143. package/dist/prepare/wkbParser.d.ts +2 -0
  144. package/dist/prepare/wkbParser.d.ts.map +1 -1
  145. package/dist/prepare/wkbParser.js +1 -0
  146. package/dist/prepare/wkbParser.js.map +1 -1
  147. package/dist/protomapsStyles.d.ts +18 -0
  148. package/dist/protomapsStyles.d.ts.map +1 -0
  149. package/dist/protomapsStyles.js +38 -0
  150. package/dist/protomapsStyles.js.map +1 -0
  151. package/dist/types.d.ts +13 -0
  152. package/dist/types.d.ts.map +1 -1
  153. package/dist/types.js.map +1 -1
  154. package/package.json +11 -9
@@ -1 +1 @@
1
- {"version":3,"file":"MapSettingsControls.js","sourceRoot":"","sources":["../src/MapSettingsControls.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n getTableDisplayName,\n getTableIdentity,\n isColumnCategorical,\n isColumnNumeric,\n isColumnQuantitative,\n type DataTable,\n type TableColumn,\n} from '@sqlrooms/duckdb';\nimport {\n Button,\n cn,\n Combobox,\n CopyButton,\n ScrollArea,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@sqlrooms/ui';\nimport {CodeIcon, TableIcon} from 'lucide-react';\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\n\nexport const DeckMapSettingsField: FC<\n PropsWithChildren<{label: string; required?: boolean}>\n> = ({label, required, children}) => (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs font-medium\">\n {label}\n {required && <span className=\"text-destructive ml-1\">*</span>}\n </label>\n <div className=\"grid items-end gap-2\">{children}</div>\n </div>\n);\n\nexport type DeckMapColumnKind =\n | 'all'\n | 'numeric'\n | 'quantitative'\n | 'categorical';\n\nexport function filterDeckMapColumns(\n columns: TableColumn[],\n kind: DeckMapColumnKind,\n) {\n if (kind === 'all') return columns;\n return columns.filter((column) => {\n if (!column.type) return false;\n if (kind === 'numeric') return isColumnNumeric(column.type);\n if (kind === 'quantitative') return isColumnQuantitative(column.type);\n return isColumnCategorical(column.type);\n });\n}\n\nconst DeckMapColumnsContext = createContext<TableColumn[]>([]);\n\nexport const DeckMapColumnsProvider: FC<\n PropsWithChildren<{columns: TableColumn[]}>\n> = ({columns, children}) => (\n <DeckMapColumnsContext.Provider value={columns}>\n {children}\n </DeckMapColumnsContext.Provider>\n);\n\nexport type DeckMapColumnSelectorProps = {\n columns?: TableColumn[];\n kind?: DeckMapColumnKind;\n value?: string;\n onChange: (value: string) => void;\n placeholder?: string;\n disabled?: boolean;\n};\n\nconst DeckMapColumnSelectorRoot: FC<DeckMapColumnSelectorProps> = ({\n columns,\n kind = 'all',\n value,\n onChange,\n placeholder = 'Select column…',\n disabled,\n}) => {\n const contextColumns = useContext(DeckMapColumnsContext);\n const options = filterDeckMapColumns(columns ?? contextColumns, kind);\n const selectedColumn = options.find((column) => column.name === value);\n const isMissing = Boolean(value && !selectedColumn);\n return (\n <Combobox value={value ?? ''} onChange={onChange} disabled={disabled}>\n <Combobox.Trigger\n className={cn(\n 'w-full',\n isMissing && 'border-destructive/60 bg-destructive/5',\n )}\n >\n {selectedColumn ? (\n <span className=\"flex min-w-0 items-baseline gap-1\">\n <span className=\"truncate\">{selectedColumn.name}</span>\n <span className=\"text-muted-foreground truncate text-[8px]\">\n {selectedColumn.type}\n </span>\n </span>\n ) : value ? (\n <span className=\"text-destructive truncate\">{value} (missing)</span>\n ) : (\n <span className=\"text-muted-foreground truncate\">{placeholder}</span>\n )}\n </Combobox.Trigger>\n <Combobox.Content\n searchable\n searchPlaceholder=\"Search columns...\"\n emptyMessage=\"No matching column.\"\n >\n {options.map((column) => (\n <Combobox.Item key={column.name} value={column.name}>\n <span className=\"truncate\">{column.name}</span>\n <span className=\"text-muted-foreground ml-auto text-[8px]\">\n {column.type}\n </span>\n </Combobox.Item>\n ))}\n </Combobox.Content>\n </Combobox>\n );\n};\n\nexport const DeckMapColumnSelector = Object.assign(DeckMapColumnSelectorRoot, {\n Numeric: (props: Omit<DeckMapColumnSelectorProps, 'kind'>) => (\n <DeckMapColumnSelectorRoot {...props} kind=\"numeric\" />\n ),\n Quantitative: (props: Omit<DeckMapColumnSelectorProps, 'kind'>) => (\n <DeckMapColumnSelectorRoot {...props} kind=\"quantitative\" />\n ),\n Categorical: (props: Omit<DeckMapColumnSelectorProps, 'kind'>) => (\n <DeckMapColumnSelectorRoot {...props} kind=\"categorical\" />\n ),\n});\n\nexport const DeckMapTableSelector: FC<{\n tables: DataTable[];\n value?: DataTable;\n onChange: (table: DataTable) => void;\n disabled?: boolean;\n}> = ({tables, value, onChange, disabled}) => {\n const identity = value ? getTableIdentity(value.table) : '';\n return (\n <Combobox\n value={identity}\n onChange={(nextIdentity) => {\n const table = tables.find(\n (candidate) => getTableIdentity(candidate.table) === nextIdentity,\n );\n if (table) onChange(table);\n }}\n disabled={disabled}\n >\n <Combobox.Trigger className=\"w-full font-mono\">\n <span className=\"flex min-w-0 items-center gap-2\">\n <TableIcon className=\"text-muted-foreground h-3.5 w-3.5 shrink-0\" />\n <span className=\"truncate\">\n {value ? getTableDisplayName(value.table) : 'Select table...'}\n </span>\n </span>\n </Combobox.Trigger>\n <Combobox.Content\n searchable\n searchPlaceholder=\"Search tables...\"\n emptyMessage=\"No tables found.\"\n >\n {tables.map((table) => {\n const tableIdentity = getTableIdentity(table.table);\n return (\n <Combobox.Item\n key={tableIdentity}\n value={tableIdentity}\n keywords={[\n getTableDisplayName(table.table),\n table.table.schema ?? '',\n table.table.database ?? '',\n ]}\n >\n <span className=\"truncate font-mono\">\n {getTableDisplayName(table.table)}\n </span>\n {table.isView ? (\n <span className=\"text-muted-foreground ml-auto text-[10px]\">\n view\n </span>\n ) : null}\n </Combobox.Item>\n );\n })}\n </Combobox.Content>\n </Combobox>\n );\n};\n\nexport const DeckMapCodeViewToggleButton: FC<{\n selected: boolean;\n onClick: () => void;\n label?: string;\n}> = ({selected, onClick, label: labelProp}) => {\n const label = labelProp ?? (selected ? 'Show settings' : 'View code');\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant={selected ? 'secondary' : 'ghost'}\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={onClick}\n aria-label={label}\n aria-pressed={selected}\n >\n <CodeIcon className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n );\n};\n\nexport const DeckMapCodeViewerPanel: FC<{\n value: string;\n copyTooltipLabel?: string;\n}> = ({value, copyTooltipLabel = 'Copy map config'}) => (\n <ScrollArea className=\"min-h-0 flex-1\">\n <div className=\"h-full p-2\">\n <div className=\"border-input relative h-full overflow-hidden rounded-md border\">\n <pre className=\"h-full overflow-auto p-3 pr-12 font-mono text-xs whitespace-pre-wrap\">\n {value}\n </pre>\n <div className=\"bg-background absolute top-2 right-2 rounded-md border\">\n <CopyButton\n text={value}\n size=\"xs\"\n tooltipLabel={copyTooltipLabel}\n disabled={!value.trim()}\n />\n </div>\n </div>\n </div>\n </ScrollArea>\n);\n"]}
1
+ {"version":3,"file":"MapSettingsControls.js","sourceRoot":"","sources":["../src/MapSettingsControls.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,GAGtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,MAAM,EACN,EAAE,EACF,QAAQ,EACR,UAAU,EACV,UAAU,EACV,OAAO,EACP,cAAc,EACd,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAC,QAAQ,EAAE,SAAS,EAAC,MAAM,cAAc,CAAC;AACjD,OAAO,EACL,aAAa,EACb,UAAU,GAGX,MAAM,OAAO,CAAC;AAEf,MAAM,CAAC,MAAM,oBAAoB,GAE7B,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAC,EAAE,EAAE,CAAC,CACnC,eAAK,SAAS,EAAC,qBAAqB,aAClC,iBAAO,SAAS,EAAC,qBAAqB,aACnC,KAAK,EACL,QAAQ,IAAI,eAAM,SAAS,EAAC,uBAAuB,kBAAS,IACvD,EACR,cAAK,SAAS,EAAC,sBAAsB,YAAE,QAAQ,GAAO,IAClD,CACP,CAAC;AAUF,uFAAuF;AACvF,MAAM,UAAU,wBAAwB,CAAC,MAAmB;IAC1D,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAC/B,IAAI,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,SAAS,CAAC;AACzD,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,+BAA+B,CAAC,MAAmB;IACjE,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,CACL,QAAQ,KAAK,QAAQ;QACrB,QAAQ,KAAK,SAAS;QACtB,QAAQ,KAAK,QAAQ;QACrB,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CACjC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,OAAsB,EACtB,IAAuB;IAEvB,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IACnC,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAC/B,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5D,IAAI,IAAI,KAAK,cAAc;YAAE,OAAO,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtE,IAAI,IAAI,KAAK,WAAW;YAAE,OAAO,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAClE,OAAO,+BAA+B,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,qBAAqB,GAAG,aAAa,CAAgB,EAAE,CAAC,CAAC;AAE/D,MAAM,CAAC,MAAM,sBAAsB,GAE/B,CAAC,EAAC,OAAO,EAAE,QAAQ,EAAC,EAAE,EAAE,CAAC,CAC3B,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,OAAO,YAC3C,QAAQ,GACsB,CAClC,CAAC;AAWF,MAAM,yBAAyB,GAAmC,CAAC,EACjE,OAAO,EACP,IAAI,GAAG,KAAK,EACZ,KAAK,EACL,QAAQ,EACR,WAAW,GAAG,gBAAgB,EAC9B,QAAQ,GACT,EAAE,EAAE;IACH,MAAM,cAAc,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,IAAI,cAAc,EAAE,IAAI,CAAC,CAAC;IACtE,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,cAAc,CAAC,CAAC;IACpD,OAAO,CACL,MAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,aAClE,KAAC,QAAQ,CAAC,OAAO,IACf,SAAS,EAAE,EAAE,CACX,QAAQ,EACR,SAAS,IAAI,wCAAwC,CACtD,YAEA,cAAc,CAAC,CAAC,CAAC,CAChB,gBAAM,SAAS,EAAC,mCAAmC,aACjD,eAAM,SAAS,EAAC,UAAU,YAAE,cAAc,CAAC,IAAI,GAAQ,EACvD,eAAM,SAAS,EAAC,2CAA2C,YACxD,cAAc,CAAC,IAAI,GACf,IACF,CACR,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CACV,gBAAM,SAAS,EAAC,2BAA2B,aAAE,KAAK,kBAAkB,CACrE,CAAC,CAAC,CAAC,CACF,eAAM,SAAS,EAAC,gCAAgC,YAAE,WAAW,GAAQ,CACtE,GACgB,EACnB,KAAC,QAAQ,CAAC,OAAO,IACf,UAAU,QACV,iBAAiB,EAAC,mBAAmB,EACrC,YAAY,EAAC,qBAAqB,YAEjC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACvB,MAAC,QAAQ,CAAC,IAAI,IAAmB,KAAK,EAAE,MAAM,CAAC,IAAI,aACjD,eAAM,SAAS,EAAC,UAAU,YAAE,MAAM,CAAC,IAAI,GAAQ,EAC/C,eAAM,SAAS,EAAC,0CAA0C,YACvD,MAAM,CAAC,IAAI,GACP,KAJW,MAAM,CAAC,IAAI,CAKf,CACjB,CAAC,GACe,IACV,CACZ,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,CAAC,yBAAyB,EAAE;IAC5E,OAAO,EAAE,CAAC,KAA+C,EAAE,EAAE,CAAC,CAC5D,KAAC,yBAAyB,OAAK,KAAK,EAAE,IAAI,EAAC,SAAS,GAAG,CACxD;IACD,YAAY,EAAE,CAAC,KAA+C,EAAE,EAAE,CAAC,CACjE,KAAC,yBAAyB,OAAK,KAAK,EAAE,IAAI,EAAC,cAAc,GAAG,CAC7D;IACD,WAAW,EAAE,CAAC,KAA+C,EAAE,EAAE,CAAC,CAChE,KAAC,yBAAyB,OAAK,KAAK,EAAE,IAAI,EAAC,aAAa,GAAG,CAC5D;IACD,SAAS,EAAE,CAAC,KAA+C,EAAE,EAAE,CAAC,CAC9D,KAAC,yBAAyB,OAAK,KAAK,EAAE,IAAI,EAAC,WAAW,GAAG,CAC1D;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAK5B,CAAC,EAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAC,EAAE,EAAE;IAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,OAAO,CACL,MAAC,QAAQ,IACP,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,CAAC,YAAY,EAAE,EAAE;YACzB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CACvB,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,YAAY,CAClE,CAAC;YACF,IAAI,KAAK;gBAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,EACD,QAAQ,EAAE,QAAQ,aAElB,KAAC,QAAQ,CAAC,OAAO,IAAC,SAAS,EAAC,kBAAkB,YAC5C,gBAAM,SAAS,EAAC,iCAAiC,aAC/C,KAAC,SAAS,IAAC,SAAS,EAAC,4CAA4C,GAAG,EACpE,eAAM,SAAS,EAAC,UAAU,YACvB,KAAK,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,GACxD,IACF,GACU,EACnB,KAAC,QAAQ,CAAC,OAAO,IACf,UAAU,QACV,iBAAiB,EAAC,kBAAkB,EACpC,YAAY,EAAC,kBAAkB,YAE9B,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;oBACpB,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBACpD,OAAO,CACL,MAAC,QAAQ,CAAC,IAAI,IAEZ,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE;4BACR,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC;4BAChC,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE;4BACxB,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE;yBAC3B,aAED,eAAM,SAAS,EAAC,oBAAoB,YACjC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,GAC5B,EACN,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CACd,eAAM,SAAS,EAAC,2CAA2C,qBAEpD,CACR,CAAC,CAAC,CAAC,IAAI,KAfH,aAAa,CAgBJ,CACjB,CAAC;gBACJ,CAAC,CAAC,GACe,IACV,CACZ,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAInC,CAAC,EAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,EAAE,EAAE;IAC7C,MAAM,KAAK,GAAG,SAAS,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACtE,OAAO,CACL,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,EACzC,IAAI,EAAC,MAAM,EACX,SAAS,EAAC,SAAS,EACnB,OAAO,EAAE,OAAO,gBACJ,KAAK,kBACH,QAAQ,YAEtB,KAAC,QAAQ,IAAC,SAAS,EAAC,aAAa,GAAG,GAC7B,GACM,EACjB,KAAC,cAAc,cAAE,KAAK,GAAkB,IAChC,CACX,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAG9B,CAAC,EAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,EAAC,EAAE,EAAE,CAAC,CACtD,KAAC,UAAU,IAAC,SAAS,EAAC,gBAAgB,YACpC,cAAK,SAAS,EAAC,YAAY,YACzB,eAAK,SAAS,EAAC,gEAAgE,aAC7E,cAAK,SAAS,EAAC,sEAAsE,YAClF,KAAK,GACF,EACN,cAAK,SAAS,EAAC,wDAAwD,YACrE,KAAC,UAAU,IACT,IAAI,EAAE,KAAK,EACX,IAAI,EAAC,IAAI,EACT,YAAY,EAAE,gBAAgB,EAC9B,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,GACvB,GACE,IACF,GACF,GACK,CACd,CAAC","sourcesContent":["import {\n getTableDisplayName,\n getTableIdentity,\n isColumnCategorical,\n isColumnNumeric,\n isColumnQuantitative,\n getColumnTypeCategory,\n type DataTable,\n type TableColumn,\n} from '@sqlrooms/duckdb';\nimport {\n Button,\n cn,\n Combobox,\n CopyButton,\n ScrollArea,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@sqlrooms/ui';\nimport {CodeIcon, TableIcon} from 'lucide-react';\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\n\nexport const DeckMapSettingsField: FC<\n PropsWithChildren<{label: string; required?: boolean}>\n> = ({label, required, children}) => (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs font-medium\">\n {label}\n {required && <span className=\"text-destructive ml-1\">*</span>}\n </label>\n <div className=\"grid items-end gap-2\">{children}</div>\n </div>\n);\n\nexport type DeckMapColumnKind =\n | 'all'\n | 'numeric'\n | 'quantitative'\n | 'categorical'\n /** Numeric/temporal + string columns usable for color scales. */\n | 'colorable';\n\n/** True for columns that can drive a color scale (excludes geometry blobs/structs). */\nexport function isDeckMapColorableColumn(column: TableColumn): boolean {\n if (!column.type) return false;\n if (isColumnQuantitative(column.type)) return true;\n const category = getColumnTypeCategory(column.type);\n return category === 'string' || category === 'boolean';\n}\n\n/** String/boolean (and binary) fields that need a categorical color scale. */\nexport function isDeckMapCategoricalColorColumn(column: TableColumn): boolean {\n if (!column.type || isColumnQuantitative(column.type)) return false;\n const category = getColumnTypeCategory(column.type);\n return (\n category === 'string' ||\n category === 'boolean' ||\n category === 'binary' ||\n isColumnCategorical(column.type)\n );\n}\n\nexport function filterDeckMapColumns(\n columns: TableColumn[],\n kind: DeckMapColumnKind,\n) {\n if (kind === 'all') return columns;\n return columns.filter((column) => {\n if (!column.type) return false;\n if (kind === 'numeric') return isColumnNumeric(column.type);\n if (kind === 'quantitative') return isColumnQuantitative(column.type);\n if (kind === 'colorable') return isDeckMapColorableColumn(column);\n return isDeckMapCategoricalColorColumn(column);\n });\n}\n\nconst DeckMapColumnsContext = createContext<TableColumn[]>([]);\n\nexport const DeckMapColumnsProvider: FC<\n PropsWithChildren<{columns: TableColumn[]}>\n> = ({columns, children}) => (\n <DeckMapColumnsContext.Provider value={columns}>\n {children}\n </DeckMapColumnsContext.Provider>\n);\n\nexport type DeckMapColumnSelectorProps = {\n columns?: TableColumn[];\n kind?: DeckMapColumnKind;\n value?: string;\n onChange: (value: string) => void;\n placeholder?: string;\n disabled?: boolean;\n};\n\nconst DeckMapColumnSelectorRoot: FC<DeckMapColumnSelectorProps> = ({\n columns,\n kind = 'all',\n value,\n onChange,\n placeholder = 'Select column…',\n disabled,\n}) => {\n const contextColumns = useContext(DeckMapColumnsContext);\n const options = filterDeckMapColumns(columns ?? contextColumns, kind);\n const selectedColumn = options.find((column) => column.name === value);\n const isMissing = Boolean(value && !selectedColumn);\n return (\n <Combobox value={value ?? ''} onChange={onChange} disabled={disabled}>\n <Combobox.Trigger\n className={cn(\n 'w-full',\n isMissing && 'border-destructive/60 bg-destructive/5',\n )}\n >\n {selectedColumn ? (\n <span className=\"flex min-w-0 items-baseline gap-1\">\n <span className=\"truncate\">{selectedColumn.name}</span>\n <span className=\"text-muted-foreground truncate text-[8px]\">\n {selectedColumn.type}\n </span>\n </span>\n ) : value ? (\n <span className=\"text-destructive truncate\">{value} (missing)</span>\n ) : (\n <span className=\"text-muted-foreground truncate\">{placeholder}</span>\n )}\n </Combobox.Trigger>\n <Combobox.Content\n searchable\n searchPlaceholder=\"Search columns...\"\n emptyMessage=\"No matching column.\"\n >\n {options.map((column) => (\n <Combobox.Item key={column.name} value={column.name}>\n <span className=\"truncate\">{column.name}</span>\n <span className=\"text-muted-foreground ml-auto text-[8px]\">\n {column.type}\n </span>\n </Combobox.Item>\n ))}\n </Combobox.Content>\n </Combobox>\n );\n};\n\nexport const DeckMapColumnSelector = Object.assign(DeckMapColumnSelectorRoot, {\n Numeric: (props: Omit<DeckMapColumnSelectorProps, 'kind'>) => (\n <DeckMapColumnSelectorRoot {...props} kind=\"numeric\" />\n ),\n Quantitative: (props: Omit<DeckMapColumnSelectorProps, 'kind'>) => (\n <DeckMapColumnSelectorRoot {...props} kind=\"quantitative\" />\n ),\n Categorical: (props: Omit<DeckMapColumnSelectorProps, 'kind'>) => (\n <DeckMapColumnSelectorRoot {...props} kind=\"categorical\" />\n ),\n Colorable: (props: Omit<DeckMapColumnSelectorProps, 'kind'>) => (\n <DeckMapColumnSelectorRoot {...props} kind=\"colorable\" />\n ),\n});\n\nexport const DeckMapTableSelector: FC<{\n tables: DataTable[];\n value?: DataTable;\n onChange: (table: DataTable) => void;\n disabled?: boolean;\n}> = ({tables, value, onChange, disabled}) => {\n const identity = value ? getTableIdentity(value.table) : '';\n return (\n <Combobox\n value={identity}\n onChange={(nextIdentity) => {\n const table = tables.find(\n (candidate) => getTableIdentity(candidate.table) === nextIdentity,\n );\n if (table) onChange(table);\n }}\n disabled={disabled}\n >\n <Combobox.Trigger className=\"w-full font-mono\">\n <span className=\"flex min-w-0 items-center gap-2\">\n <TableIcon className=\"text-muted-foreground h-3.5 w-3.5 shrink-0\" />\n <span className=\"truncate\">\n {value ? getTableDisplayName(value.table) : 'Select table...'}\n </span>\n </span>\n </Combobox.Trigger>\n <Combobox.Content\n searchable\n searchPlaceholder=\"Search tables...\"\n emptyMessage=\"No tables found.\"\n >\n {tables.map((table) => {\n const tableIdentity = getTableIdentity(table.table);\n return (\n <Combobox.Item\n key={tableIdentity}\n value={tableIdentity}\n keywords={[\n getTableDisplayName(table.table),\n table.table.schema ?? '',\n table.table.database ?? '',\n ]}\n >\n <span className=\"truncate font-mono\">\n {getTableDisplayName(table.table)}\n </span>\n {table.isView ? (\n <span className=\"text-muted-foreground ml-auto text-[10px]\">\n view\n </span>\n ) : null}\n </Combobox.Item>\n );\n })}\n </Combobox.Content>\n </Combobox>\n );\n};\n\nexport const DeckMapCodeViewToggleButton: FC<{\n selected: boolean;\n onClick: () => void;\n label?: string;\n}> = ({selected, onClick, label: labelProp}) => {\n const label = labelProp ?? (selected ? 'Show settings' : 'View code');\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant={selected ? 'secondary' : 'ghost'}\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={onClick}\n aria-label={label}\n aria-pressed={selected}\n >\n <CodeIcon className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n );\n};\n\nexport const DeckMapCodeViewerPanel: FC<{\n value: string;\n copyTooltipLabel?: string;\n}> = ({value, copyTooltipLabel = 'Copy map config'}) => (\n <ScrollArea className=\"min-h-0 flex-1\">\n <div className=\"h-full p-2\">\n <div className=\"border-input relative h-full overflow-hidden rounded-md border\">\n <pre className=\"h-full overflow-auto p-3 pr-12 font-mono text-xs whitespace-pre-wrap\">\n {value}\n </pre>\n <div className=\"bg-background absolute top-2 right-2 rounded-md border\">\n <CopyButton\n text={value}\n size=\"xs\"\n tooltipLabel={copyTooltipLabel}\n disabled={!value.trim()}\n />\n </div>\n </div>\n </div>\n </ScrollArea>\n);\n"]}
package/dist/ai.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"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"}
package/dist/ai.js CHANGED
@@ -7,6 +7,8 @@ import { DECK_TABLE_DATASET_SOURCE_RELATION } from './datasets/tableDatasetSql';
7
7
  import { getFirstDatasetSourceTableName, hasSqlOnlyDatasetSource, } from './datasetSourceUtils';
8
8
  import { getDeckMapSharedAiContractRules } from './mapAiSharedInstructions';
9
9
  import { prepareAiDeckMapConfig } from './aiNormalize';
10
+ import { assertDeckMapResourceConfig } from './mapResourceAuthoring';
11
+ import { asDeckJsonMapConfig, withPreservedDeckMapStyle } from './mapConfig';
10
12
  export { getFirstDatasetSourceTableName, hasSqlOnlyDatasetSource };
11
13
  const COLOR_SCHEME_PROMPT_LISTS = formatColorSchemePromptLists();
12
14
  export const DECK_MAP_AI_INSTRUCTIONS = `
@@ -23,7 +25,7 @@ ${getDeckMapSharedAiContractRules()}
23
25
  - LAYER SELECTION: Choose the layer type based on the geometry type in the data.
24
26
  IMPORTANT: Only create a layer if the table contains data suitable for that layer type, or if you can transform the data into the required format with transformSql or a standalone sqlQuery. Do NOT create a layer if the data is clearly incompatible (e.g. do not create a path layer from point-only data without aggregation, do not create a polygon layer from point coordinates, do not create an arc layer without origin-destination pairs).
25
27
  - Point data (lon/lat coordinates, point geometry): GeoArrowScatterplotLayer (Point layer), GeoArrowHeatmapLayer, GeoArrowColumnLayer. Requires lon/lat columns (via ST_Point transformSql) or a Point geometry column — follow the shared Point-position rules above.
26
- - Polygon data (building footprints, boundaries, areas, parcels, zones): GeoArrowPolygonLayer or GeoArrowSolidPolygonLayer for uniform Polygon columns. Use GeoJsonLayer for WKB/WKT MultiPolygon columns so separate polygon parts retain their nesting.
28
+ - Polygon data (building footprints, boundaries, areas, parcels, zones): GeoArrowPolygonLayer for uniform Polygon columns. Use GeoJsonLayer for WKB/WKT MultiPolygon columns so separate polygon parts retain their nesting.
27
29
  - Line data (roads, routes, paths, rivers): GeoArrowPathLayer. Requires LineString geometry (or a single-part MultiLineString). Multi-part MultiLineString cannot be rendered as one path — explode/merge with ST_Dump / ST_LineMerge first. If the table has one row per waypoint (path_id/route_id + order/sequence + lat/lon), aggregate with transformSql: "SELECT path_id, label, ST_AsWKB(ST_MakeLine(LIST(ST_Point(lon, lat) ORDER BY waypoint_order))) AS geom FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} GROUP BY path_id, label". Set geometryColumn to "geom" and geometryEncodingHint to "wkb". If linestring geom already exists, use it directly (or SELECT * EXCLUDE (geom), ST_AsWKB(geom) AS geom ... WHERE ST_GeometryType(geom) = 'LINESTRING').
28
30
  - Animated trip data (routes with timestamps): GeoArrowTripsLayer (see shared trips-vs-arc rule). One row per trip: LineString geom + timestamps list (same order/length as vertices).
29
31
  (1) Waypoint rows (trip_id/path_id + lat/lon + order/time): GROUP BY trip id. Example: "SELECT trip_id, ANY_VALUE(label) AS label, ST_AsWKB(ST_MakeLine(LIST(ST_Point(lon, lat) ORDER BY waypoint_order))) AS geom, LIST(timestamp ORDER BY waypoint_order) AS timestamps FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} GROUP BY trip_id". Keep attrs with ANY_VALUE(col). Use ST_MakeLine(LIST(...)) only — never ST_MakeLine(ST_Point(...) ORDER BY ...); always GROUP BY the trip id.
@@ -54,7 +56,7 @@ ${getDeckMapSharedAiContractRules()}
54
56
  - Create maps with a SINGLE layer unless the user explicitly asks for multiple layers. If you think multiple layers would better serve the user's request, ask the user for confirmation before adding them.
55
57
  - IMPORTANT: Browsers limit the number of active WebGL contexts (typically 8–16 per page). Each map panel uses one context. Do NOT create more than 4–5 map panels in a single dashboard — exceeding the limit causes older maps to lose their rendering context and show errors. If the user asks for many datasets, prefer combining compatible layers into fewer maps rather than creating one map per dataset.
56
58
  - After calling create_dashboard_map, call list_dashboard_panels before your final response and check the map panel issue. If it has a render-error, repair the map config in place instead of saying the map is complete.
57
- - IMPORTANT: Dashboard map tools replace the full panel config — always include datasets and layers on updates. Omitting datasets is only valid for worksheet sparse patches that merge with durable state.
59
+ - IMPORTANT: Dashboard map tools replace the full panel config — always include datasets and layers on updates. Omitting datasets is only valid for document sparse patches that merge with durable state.
58
60
  - SWITCHING LAYER TYPE: On type switch/replace, send only the new layer (replaceLayers: true for merge patches; full desired layers list for dashboard updates). Do not leave the old layer as visible: false.
59
61
  `;
60
62
  function createDeckMapDashboardExtraTools(extraTools, prepareOptions) {
@@ -204,16 +206,19 @@ export const DeckMapDashboardToolParameters = DeckMapConfigToolParameters.extend
204
206
  export { normalizeAiDeckMapConfig, prepareAiDeckMapConfig, validateAndFixColorScaleFields, } from './aiNormalize';
205
207
  function cloneConfig(config, options) {
206
208
  const normalized = prepareAiDeckMapConfig(config, options);
207
- return JSON.parse(JSON.stringify(normalized));
209
+ const cloned = JSON.parse(JSON.stringify(normalized));
210
+ assertDeckMapResourceConfig(cloned);
211
+ return cloned;
208
212
  }
209
213
  /**
210
214
  * Creates a dashboard-compatible Deck map panel from the native map config
211
215
  * used by AI tools and embeddable map surfaces.
212
216
  */
213
217
  export function createDeckMapPanelFromNativeConfig(params, options) {
218
+ const config = cloneConfig(params.config, options);
214
219
  return createDeckMapDashboardPanelConfig({
215
220
  title: params.title || 'Map',
216
- ...cloneConfig(params.config, options),
221
+ ...config,
217
222
  });
218
223
  }
219
224
  export function createDeckMapConfigTool() {
@@ -277,11 +282,12 @@ Use when: the user asks for a map in a dashboard. Author the map using native De
277
282
  try {
278
283
  // Prepare/validate before mutating dashboard selection so a rejected
279
284
  // config does not switch the active table as a side effect.
280
- const panel = createDeckMapPanelFromNativeConfig(params, {
285
+ const config = cloneConfig(params.config, {
281
286
  resolveTable: (name) => databaseAdapter.findTable(name),
282
287
  stripCatalogNames,
283
288
  });
284
- const tableName = params.tableName ?? getFirstDatasetSourceTableName(panel.config);
289
+ const title = params.title || 'Map';
290
+ const tableName = params.tableName ?? getFirstDatasetSourceTableName(config);
285
291
  if (tableName) {
286
292
  ensureTable(databaseAdapter, tableName);
287
293
  }
@@ -289,24 +295,26 @@ Use when: the user asks for a map in a dashboard. Author the map using native De
289
295
  await dashboardAdapter.setSelectedTable(tableName);
290
296
  }
291
297
  if (params.panelId) {
292
- ensurePanel(dashboardAdapter, params.panelId, DECK_MAP_DASHBOARD_PANEL_TYPE);
298
+ const existingPanel = ensurePanel(dashboardAdapter, params.panelId, DECK_MAP_DASHBOARD_PANEL_TYPE);
299
+ const updatedConfig = withPreservedDeckMapStyle(config, asDeckJsonMapConfig(existingPanel.config));
293
300
  await dashboardAdapter.updatePanel(params.panelId, {
294
- title: panel.title,
295
- config: panel.config,
301
+ title,
302
+ config: updatedConfig,
296
303
  });
297
304
  return {
298
305
  llmResult: {
299
306
  success: true,
300
- details: `Updated map panel "${panel.title}".`,
307
+ details: `Updated map panel "${title}".`,
301
308
  data: {
302
309
  panelId: params.panelId,
303
- title: panel.title,
310
+ title,
304
311
  type: DECK_MAP_DASHBOARD_PANEL_TYPE,
305
- config: panel.config,
312
+ config: updatedConfig,
306
313
  },
307
314
  },
308
315
  };
309
316
  }
317
+ const panel = createDeckMapDashboardPanelConfig({ title, ...config });
310
318
  const panelId = await dashboardAdapter.addPanel(panel);
311
319
  return {
312
320
  llmResult: {
package/dist/ai.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"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","sourcesContent":["import {tool, type Tool} from 'ai';\nimport {z} from 'zod';\nimport {formatColorSchemePromptLists} from '@sqlrooms/color-scales/colorSchemeNames';\nimport {\n DashboardAiAdapter,\n MAP_TOOL_KEY,\n createDashboardAgentTool,\n createDashboardAiTools as createMosaicDashboardAiTools,\n type CreateDashboardAgentToolOptions,\n type CreateDashboardAiToolsOptions,\n ensureTable,\n ensurePanel,\n DatabaseAiAdapter,\n ExtraDashboardAiToolsFactory,\n ExtraDashboardAiToolsParams,\n MosaicDashboardStoreState,\n} from '@sqlrooms/mosaic';\nimport {\n createDeckMapDashboardPanelConfig,\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n type DeckMapDashboardPanelConfig,\n} from './dashboardConfig';\nimport {DECK_TABLE_DATASET_SOURCE_RELATION} from './datasets/tableDatasetSql';\nimport {\n getFirstDatasetSourceTableName,\n hasSqlOnlyDatasetSource,\n} from './datasetSourceUtils';\nimport {getDeckMapSharedAiContractRules} from './mapAiSharedInstructions';\nimport {prepareAiDeckMapConfig} from './aiNormalize';\nimport type {PrepareAiDeckMapConfigOptions} from './aiNormalize';\n\nexport {getFirstDatasetSourceTableName, hasSqlOnlyDatasetSource};\n\nconst COLOR_SCHEME_PROMPT_LISTS = formatColorSchemePromptLists();\n\nexport const DECK_MAP_AI_INSTRUCTIONS = `\nDeck map tools:\n- create_deck_map_config validates and returns a reusable native Deck JSON map config without requiring a dashboard artifact.\n- create_dashboard_map creates or updates an interactive map panel inside a dashboard from a native Deck JSON map config.\n- Use map tools when the user asks for a map, geospatial/spatial visualization, locations, longitude/latitude data, or geometry columns.\n- CONFIG MODE: Every map config must include a configMode field (\"basic\" or \"custom\") that determines how the map was authored and whether the UI settings panel is available.\n - \"basic\" (default): Use for straightforward requests — single layer, standard color scale, simple geometry binding. Stick ONLY to properties that the UI configurator supports: layer @@type, visibility, color scale (@@function colorScale), point radius (numeric getRadius with radiusUnits), line width (numeric getWidth with widthUnits), geometry/H3/arc column bindings, extrusion with a single elevation column (\"@@=columnName\" or {\"@@function\":\"scale\",\"field\":\"...\",\"type\":\"linear\",\"domain\":\"auto\",\"range\":[0,200]}). Do NOT use free-form string expressions (e.g. \"floors * 3\"), custom extensions, multiple layers, or advanced deck.gl props in basic mode. The user can fine-tune these maps through the settings panel.\n - \"custom\": Use when the request demands creative, complex, or advanced visualization — multiple layers, free-form data-driven accessors, custom color arrays, advanced deck.gl props (opacity, transitions, material, highlightColor, etc.), layer extensions, or any props not representable in the UI configurator. The UI settings panel will be disabled for custom configs; users edit via the JSON editor instead.\n - Decision rule: If the map can be fully expressed with a single layer + basic color scale + simple numeric radius/width (+ optional single elevation column), use \"basic\". Extruded GeoArrowColumnLayer / polygon maps with one elevation field must stay \"basic\" so the settings panel remains available. Use \"custom\" only when basic cannot express the request.\n- Author maps with config.spec.layers using Deck JSON layer classes in @@type, such as GeoArrowScatterplotLayer, GeoArrowHeatmapLayer, GeoArrowPolygonLayer, GeoArrowPathLayer, GeoArrowTripsLayer, GeoArrowArcLayer, GeoArrowH3HexagonLayer, or GeoJsonLayer. Always use the full GeoArrow-prefixed class name when choosing a GeoArrow layer (e.g. \"GeoArrowScatterplotLayer\", not \"ScatterplotLayer\") — unprefixed names are not registered. Prefer a typed GeoArrow* layer when the geometry type is known; use GeoJsonLayer for mixed or generic GeoJSON/WKB feature rendering with _sqlroomsBinding.\n${getDeckMapSharedAiContractRules()}\n- LAYER SELECTION: Choose the layer type based on the geometry type in the data.\n IMPORTANT: Only create a layer if the table contains data suitable for that layer type, or if you can transform the data into the required format with transformSql or a standalone sqlQuery. Do NOT create a layer if the data is clearly incompatible (e.g. do not create a path layer from point-only data without aggregation, do not create a polygon layer from point coordinates, do not create an arc layer without origin-destination pairs).\n - Point data (lon/lat coordinates, point geometry): GeoArrowScatterplotLayer (Point layer), GeoArrowHeatmapLayer, GeoArrowColumnLayer. Requires lon/lat columns (via ST_Point transformSql) or a Point geometry column — follow the shared Point-position rules above.\n - Polygon data (building footprints, boundaries, areas, parcels, zones): GeoArrowPolygonLayer or GeoArrowSolidPolygonLayer for uniform Polygon columns. Use GeoJsonLayer for WKB/WKT MultiPolygon columns so separate polygon parts retain their nesting.\n - Line data (roads, routes, paths, rivers): GeoArrowPathLayer. Requires LineString geometry (or a single-part MultiLineString). Multi-part MultiLineString cannot be rendered as one path — explode/merge with ST_Dump / ST_LineMerge first. If the table has one row per waypoint (path_id/route_id + order/sequence + lat/lon), aggregate with transformSql: \"SELECT path_id, label, ST_AsWKB(ST_MakeLine(LIST(ST_Point(lon, lat) ORDER BY waypoint_order))) AS geom FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} GROUP BY path_id, label\". Set geometryColumn to \"geom\" and geometryEncodingHint to \"wkb\". If linestring geom already exists, use it directly (or SELECT * EXCLUDE (geom), ST_AsWKB(geom) AS geom ... WHERE ST_GeometryType(geom) = 'LINESTRING').\n - Animated trip data (routes with timestamps): GeoArrowTripsLayer (see shared trips-vs-arc rule). One row per trip: LineString geom + timestamps list (same order/length as vertices).\n (1) Waypoint rows (trip_id/path_id + lat/lon + order/time): GROUP BY trip id. Example: \"SELECT trip_id, ANY_VALUE(label) AS label, ST_AsWKB(ST_MakeLine(LIST(ST_Point(lon, lat) ORDER BY waypoint_order))) AS geom, LIST(timestamp ORDER BY waypoint_order) AS timestamps FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} GROUP BY trip_id\". Keep attrs with ANY_VALUE(col). Use ST_MakeLine(LIST(...)) only — never ST_MakeLine(ST_Point(...) ORDER BY ...); always GROUP BY the trip id.\n (2) OD pairs already one row per trip: no GROUP BY — \"SELECT trip_id, ST_AsWKB(ST_MakeLine([ST_Point(pickup_lon, pickup_lat), ST_Point(dropoff_lon, dropoff_lat)])) AS geom, [0.0, 1.0] AS timestamps FROM ${DECK_TABLE_DATASET_SOURCE_RELATION}\" (prefer [0.0, duration] when available).\n In both cases set geometryColumn to \"geom\", geometryEncodingHint to \"wkb\", and _sqlroomsBinding.timestampColumn to \"timestamps\".\n - Arc data (origin-destination pairs): GeoArrowArcLayer for arcs/connections/flows/OD links only (see shared arc-binding rule). Example transformSql: \"SELECT *, ST_AsWKB(ST_Point(source_lon, source_lat)) AS source_geom, ST_AsWKB(ST_Point(target_lon, target_lat)) AS target_geom FROM ${DECK_TABLE_DATASET_SOURCE_RELATION}\". Flat lines: \"getHeight\": 0. For H3 OD pairs use h3_cell_to_lng/lat inside ST_Point (not h3_latlng).\n - H3 hexagon data: GeoArrowH3HexagonLayer (see shared H3 rule). Include fitToData {\"dataset\":\"datasetId\"}. Valid H3 helpers: h3_cell_to_lat/lng/latlng — not h3_latlng/h3_to_lat.\n- CRITICAL geometryColumn rule: The geometryColumn field (in datasets[id].geometryColumn, _sqlroomsBinding.geometryColumn, and fitToData.geometryColumn) MUST match the exact column alias that produces the WKB geometry in the final query output — typically the \"AS geom\" alias in ST_AsWKB(...) AS geom. It must NEVER be set to a GROUP BY key, an ID column, or any other non-geometry column. For example, if the transformSql is \"SELECT path_id, ST_AsWKB(ST_MakeLine(...)) AS geom ... GROUP BY path_id\", geometryColumn must be \"geom\" (the geometry output), NOT \"path_id\" (the grouping key). Setting geometryColumn to a non-geometry column will cause the layer to fail silently.\n- CRITICAL: The transformSql and sqlQuery fields must contain ONLY a single SELECT statement. NEVER put INSTALL, LOAD, CREATE, or other DDL/meta-commands in dataset SQL — they will fail because dataset SQL is wrapped in a subquery at runtime. Extensions like h3 and spatial are pre-loaded at startup.\n - GeoJSON files typically contain polygon or multipolygon features; use polygon layers (or follow shared Point/mixed rules when the user asks for points/mixed rendering).\n- RADIUS AND WIDTH: For GeoArrowScatterplotLayer (Point layer) use numeric getRadius with radiusUnits: \"pixels\" (typically 2–6). Never use string expressions like \"field * 500\" in basic mode — they bypass pixel clamping. Data-driven size: \"@@=columnName\" only in configMode \"custom\", with radiusUnits meters so radiusMaxPixels can cap. For GeoArrowColumnLayer use \"radius\" in meters (not getRadius/radiusUnits), typically 20–200. Always set \"extruded\": true when using getElevation. For Arc/Path/Trips use numeric getWidth with widthUnits: \"pixels\" (typically 1–3).\n- ARC vs LINE: GeoArrowArcLayer renders curved 3D arcs by default. If the user asks for \"lines\" or \"straight connections\" between origin-destination pairs (not arcs), set \"getHeight\": 0 on the layer to render flat straight lines. Use arcs for flight routes or connections where the curve adds clarity; use flat lines for direct relationships, edges, or when the user explicitly requests lines.\n- ELEVATION: For extruded layers set \"extruded\": true. Prefer getElevation {\"@@function\":\"scale\",\"field\":\"...\",\"type\":\"linear\",\"domain\":\"auto\",\"range\":[0,200]} (basic-mode friendly) or \"@@=columnName\". elevationScale multiplies raw field meters — keep max visual height moderate (~hundreds of meters). Do NOT use negative elevation. For polygon building footprints with GeoArrowColumnLayer, transformSql should produce points via the shared centroid rule. CRITICAL: Extruded ColumnLayer / polygon maps need a pitched camera — set spec.initialViewState with pitch around 45–60 (and optional bearing). Top-down pitch 0 makes columns look like flat disks and appear \"missing\".\n- Bind layers to datasets with _sqlroomsBinding.dataset and put tableName, tableName+transformSql, or sqlQuery sources in config.datasets.\n- Use source.tableName for direct table-backed datasets. Use source.tableName plus source.transformSql when the map needs generated geometry or aggregation but should still follow the dashboard selected table. transformSql must read from ${DECK_TABLE_DATASET_SOURCE_RELATION}, not from the authored table name.\n- Use source.sqlQuery only for a standalone literal query that should remain pinned to the authored SQL. Dashboard selected table replacement applies only to structured tableName sources, not literal sqlQuery sources.\n- IMPORTANT: Always pass tableName in the create_dashboard_map tool params (the top-level tableName field). Use the table currently selected in the dashboard (dashboard.selectedTable from list_dashboard_panels). At runtime, the dashboard's selected table overrides structured source.tableName values — this param seeds or changes that selection.\n- IMPORTANT: If you are creating a structured table-backed map layer for a table that is NOT the currently selected dashboard table, you MUST switch the dashboard's selected table to that dataset BEFORE or WHEN calling create_dashboard_map (pass the correct tableName). Structured table-backed map panels resolve data from the dashboard's active table — if you don't switch it, the layer will query the wrong table and fail.\n- IMPORTANT: When referencing tables in tableName or sqlQuery, use ONLY the bare table name (e.g. \"my_table\") or schema-qualified name (e.g. \"main.my_table\"). NEVER include the database/catalog prefix (e.g. do NOT use \"sqlrooms-cli.main.my_table\") — the catalog does not exist in the query execution context.\n- IMPORTANT: For point data with longitude/latitude columns that should follow dashboard table switching, use source.tableName plus source.transformSql to create a geometry column, for example: \"SELECT *, ST_AsWKB(ST_Point(\\\\\"Longitude\\\\\", \\\\\"Latitude\\\\\")) AS \\\\\"__sqlrooms_geom\\\\\" FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} WHERE \\\\\"Longitude\\\\\" IS NOT NULL AND \\\\\"Latitude\\\\\" IS NOT NULL\". Set geometryColumn to the same name used in the AS clause (e.g. \"__sqlrooms_geom\") and geometryEncodingHint to \"wkb\".\n- IMPORTANT: When providing fitToData, it MUST be a flat object (NOT nested by dataset ID). Include either longitudeColumn+latitudeColumn (for point data with separate coordinate columns) OR geometryColumn (for data with a WKB geometry column like GeoJSON). For H3 hexagon layers, just specify the dataset: \"fitToData\": {\"dataset\": \"datasetId\"} — the H3 column is auto-detected from the layer binding. For GeoJSON/spatial files with a \"geom\" column, use: \"fitToData\": {\"dataset\": \"datasetId\", \"geometryColumn\": \"geom\"}. For point data use: \"fitToData\": {\"dataset\": \"datasetId\", \"longitudeColumn\": \"lon\", \"latitudeColumn\": \"lat\"}. NEVER nest fitToData as {\"datasetId\": {...}} — always use a flat object with \"dataset\" as a string field.\n- IMPORTANT: For GeoJSON or spatial files that already have a native geometry column (e.g. \"geometry\", \"geom\"), use the table directly with source.tableName (no sqlQuery needed), set the dataset's geometryColumn to \"geom\", set geometryEncodingHint to \"wkb\", and use fitToData with geometryColumn: {\"dataset\": \"datasetId\", \"geometryColumn\": \"geom\"}.\n- IMPORTANT: When a GeoJSON file (.geojson) is loaded as a table, DuckDB uses ST_Read to produce a table with a WKB \"geom\" column and all feature properties as columns. Use source.tableName, set geometryColumn to \"geom\" and geometryEncodingHint to \"wkb\". Use \"fitToData\": {\"dataset\": \"datasetId\", \"geometryColumn\": \"geom\"} to zoom to the data extent.\n- For data-driven color, use {\"@@function\":\"colorScale\", \"field\":\"...\", \"type\":\"sequential\"|\"diverging\"|\"quantize\"|\"quantile\"|\"categorical\", \"scheme\":\"...\", \"domain\":\"auto\"} on getFillColor / getLineColor / getColor / getSourceColor / getTargetColor. Key is \"@@function\" (not \"@@type\"); column goes in \"field\" (not \"column\"). Exact scheme names: ${COLOR_SCHEME_PROMPT_LISTS}. \"field\" must exist in the FINAL query output after any GROUP BY.\n- COLOR SCALE PREFERENCE: Prefer colorScale over flat fill when a useful varying column exists — numeric → sequential/quantile (quantile if skewed); categorical/string → categorical. A numeric column is useful only when min < max (not all zeros / constant); otherwise use flat fill. If the user explicitly names a column for color, honor that even when flat. Flat fill also when the user asks for one color. \"field\" must be the exact schema column name (case-sensitive; \"Magnitude\" not \"mag\"). IMPORTANT: Viridis/Plasma/Inferno/Turbo/Cividis/Magma require type \"sequential\" (not quantile/quantize). Quantile/quantize schemes must be ColorBrewer ramps such as YlOrRd, Blues, Greens, RdYlBu.\n- IMPORTANT: Enabling a color scale means adding a {\"@@function\":\"colorScale\", ...} accessor to a compatible layer color property. The top-level showLegends field only controls whether already-defined color scale legends are visible; showLegends by itself does NOT create or enable data-driven color.\n- Map panels default to a 100000-row runtime data limit; use config.dataPolicy.maxRows only when the map genuinely needs a panel-specific limit.\n- Create maps with a SINGLE layer unless the user explicitly asks for multiple layers. If you think multiple layers would better serve the user's request, ask the user for confirmation before adding them.\n- IMPORTANT: Browsers limit the number of active WebGL contexts (typically 8–16 per page). Each map panel uses one context. Do NOT create more than 4–5 map panels in a single dashboard — exceeding the limit causes older maps to lose their rendering context and show errors. If the user asks for many datasets, prefer combining compatible layers into fewer maps rather than creating one map per dataset.\n- After calling create_dashboard_map, call list_dashboard_panels before your final response and check the map panel issue. If it has a render-error, repair the map config in place instead of saying the map is complete.\n- IMPORTANT: Dashboard map tools replace the full panel config — always include datasets and layers on updates. Omitting datasets is only valid for worksheet sparse patches that merge with durable state.\n- SWITCHING LAYER TYPE: On type switch/replace, send only the new layer (replaceLayers: true for merge patches; full desired layers list for dashboard updates). Do not leave the old layer as visible: false.\n`;\n\nfunction createDeckMapDashboardExtraTools(\n extraTools?: ExtraDashboardAiToolsFactory,\n prepareOptions?: Pick<PrepareAiDeckMapConfigOptions, 'stripCatalogNames'>,\n) {\n return (params: ExtraDashboardAiToolsParams) => ({\n ...createDeckMapDashboardAiTools({\n ...params,\n stripCatalogNames: prepareOptions?.stripCatalogNames,\n }),\n ...(extraTools?.(params) ?? {}),\n });\n}\n\n/**\n * Returns AI instructions for dashboards with Deck.gl map support.\n * Provides guidance on when and how to use map visualizations.\n *\n * @returns Instructions string for AI agents\n */\nexport function getDashboardWithDeckMapAiInstructions() {\n return `${DECK_MAP_AI_INSTRUCTIONS.trim()}`;\n}\n\n/**\n * Creates dashboard AI tools with built-in Deck.gl map support.\n * Extends standard dashboard tools with map visualization capabilities.\n *\n * @param options - Dashboard AI tools configuration options\n * @returns Record mapping tool names to tool instances, including map tools\n */\nexport type CreateDashboardWithDeckMapAiToolsOptions =\n CreateDashboardAiToolsOptions & {\n /** Host-injected catalogs to strip; omit for none — deck does not hardcode any. */\n stripCatalogNames?: readonly string[];\n };\n\nexport function createDashboardWithDeckMapAiTools(\n options: CreateDashboardWithDeckMapAiToolsOptions,\n): Record<string, Tool> {\n const {stripCatalogNames, extraTools, ...rest} = options;\n return createMosaicDashboardAiTools({\n ...rest,\n extraTools: createDeckMapDashboardExtraTools(extraTools, {\n stripCatalogNames,\n }),\n });\n}\n\n/**\n * Creates a dashboard agent tool with built-in Deck.gl map support.\n * Extends the standard dashboard agent with map creation capabilities.\n *\n * @template TState - Store state type extending MosaicDashboardStoreState\n * @param options - Dashboard agent configuration options\n * @returns Dashboard agent tool with map support\n */\nexport type CreateDashboardAgentToolWithDeckMapsOptions<\n TState extends MosaicDashboardStoreState,\n> = CreateDashboardAgentToolOptions<TState> & {\n stripCatalogNames?: readonly string[];\n};\n\nexport function createDashboardAgentToolWithDeckMaps<\n TState extends MosaicDashboardStoreState,\n>(options: CreateDashboardAgentToolWithDeckMapsOptions<TState>): Tool {\n const {stripCatalogNames, extraTools, ...rest} = options;\n return createDashboardAgentTool({\n ...rest,\n additionalInstructions: [\n options.additionalInstructions,\n DECK_MAP_AI_INSTRUCTIONS.trim(),\n ]\n .filter(Boolean)\n .join('\\n\\n'),\n extraTools: createDeckMapDashboardExtraTools(extraTools, {\n stripCatalogNames,\n }),\n });\n}\n\nconst DeckMapLayerBindingConfig = z.looseObject({\n dataset: z.string().optional(),\n geometryColumn: z.string().optional(),\n geometryEncodingHint: z.enum(['geoarrow', 'wkb', 'wkt']).optional(),\n sourceGeometryColumn: z.string().optional(),\n targetGeometryColumn: z.string().optional(),\n timestampColumn: z.string().optional(),\n hexagonColumn: z.string().optional(),\n});\n\nconst DeckMapLayerSpec = z.looseObject({\n '@@type': z.string().optional(),\n id: z.string().optional(),\n _sqlroomsBinding: DeckMapLayerBindingConfig.optional(),\n});\n\nconst DeckMapSpec = z.looseObject({\n initialViewState: z.record(z.string(), z.unknown()).optional(),\n viewState: z.record(z.string(), z.unknown()).optional(),\n controller: z.unknown().optional(),\n layers: z.array(DeckMapLayerSpec).optional(),\n});\n\nconst DeckMapDatasetSource = z.looseObject({\n tableName: z.string().optional(),\n transformSql: z.string().optional(),\n sqlQuery: z.string().optional(),\n});\n\nconst DeckMapDatasetConfig = z.looseObject({\n source: DeckMapDatasetSource.optional(),\n geometryColumn: z.string().optional(),\n geometryEncodingHint: z.enum(['geoarrow', 'wkb', 'wkt']).optional(),\n});\n\nconst DeckMapDataPolicyConfig = z.looseObject({\n disabled: z.boolean().optional(),\n maxRows: z.number().int().min(1).optional(),\n reason: z.string().optional(),\n});\n\nexport const DeckMapDashboardConfigParameter = z.looseObject({\n spec: DeckMapSpec.describe(\n 'Deck JSON map spec as an object. Use spec.layers[].@@type for layer classes such as GeoArrowScatterplotLayer (Point layer), GeoArrowHeatmapLayer, GeoArrowPolygonLayer, GeoArrowPathLayer, or GeoArrowArcLayer.',\n ),\n datasets: z\n .record(z.string(), DeckMapDatasetConfig)\n .describe(\n 'Datasets keyed by dataset id. Layers bind to these ids through _sqlroomsBinding.dataset. Each dataset source may use tableName, tableName+transformSql, or sqlQuery.',\n ),\n configMode: z\n .enum(['basic', 'custom'])\n .optional()\n .describe(\n 'Config authoring mode. Use \"basic\" (default) for straightforward single-layer maps that the user can tweak via the UI settings panel. Use \"custom\" for complex, multi-layer, or creative maps that use advanced deck.gl props beyond what the UI configurator supports — the settings panel will be disabled for custom configs.',\n ),\n mapStyle: z.string().optional(),\n mapProps: z.record(z.string(), z.unknown()).optional(),\n showLegends: z\n .boolean()\n .optional()\n .describe(\n 'Whether to show color scale legends on the map. Defaults to true; omit or set true unless the user explicitly asks to hide legends.',\n ),\n interaction: z.record(z.string(), z.unknown()).optional(),\n fitToData: z\n .object({\n dataset: z.string().describe('Dataset id to compute bounds from.'),\n longitudeColumn: z\n .string()\n .optional()\n .describe('Longitude column name for point data.'),\n latitudeColumn: z\n .string()\n .optional()\n .describe('Latitude column name for point data.'),\n geometryColumn: z\n .string()\n .optional()\n .describe('WKB geometry column name for computing bounds.'),\n geometryColumns: z\n .array(z.string())\n .optional()\n .describe(\n 'Multiple WKB geometry columns whose extents are combined (e.g. arc source + target). Prefer omitting this — for GeoArrowArcLayer it is inferred from _sqlroomsBinding.',\n ),\n h3Column: z\n .string()\n .optional()\n .describe('H3 hex index column for computing bounds.'),\n padding: z.number().optional(),\n maxZoom: z.number().optional(),\n })\n .optional()\n .describe(\n 'Fit map view to data bounds. Provide dataset plus either geometryColumn (for WKB geometry) or longitudeColumn+latitudeColumn (for separate coordinate columns). For arc layers, just {\"dataset\": \"datasetId\"} is enough — source and target geometry columns are inferred from the layer binding. Example: {\"dataset\": \"myDataset\", \"geometryColumn\": \"geom\"}',\n ),\n dataPolicy: DeckMapDataPolicyConfig.optional().describe(\n 'Optional per-map runtime data policy. Maps default to 100000 rows; set maxRows for a panel-specific override or disabled=true to bypass row-count validation.',\n ),\n settingsOpen: z.boolean().optional(),\n});\n\nexport type DeckMapDashboardConfigToolConfig = z.infer<\n typeof DeckMapDashboardConfigParameter\n>;\n\nexport const DeckMapConfigToolParameters = z.object({\n title: z.string().optional().default('Map').describe('Map title.'),\n config: DeckMapDashboardConfigParameter.describe(\n 'Native Deck JSON dashboard map config. This is the canonical map representation.',\n ),\n reasoning: z\n .string()\n .describe('Brief rationale for creating the map config.'),\n});\n\nexport type DeckMapConfigToolParams = z.infer<\n typeof DeckMapConfigToolParameters\n>;\n\nexport const DeckMapDashboardToolParameters =\n DeckMapConfigToolParameters.extend({\n tableName: z\n .string()\n .optional()\n .describe(\n 'Optional table name used only to select/resolve the target dashboard table. Data sources still come from config.datasets.',\n ),\n panelId: z\n .string()\n .optional()\n .describe(\n 'Optional panel ID. If provided, updates the existing map panel instead of creating a new one.',\n ),\n reasoning: z\n .string()\n .describe('Brief rationale for creating the map panel.'),\n });\n\nexport type DeckMapDashboardToolParams = z.infer<\n typeof DeckMapDashboardToolParameters\n>;\n\nexport {\n normalizeAiDeckMapConfig,\n prepareAiDeckMapConfig,\n validateAndFixColorScaleFields,\n} from './aiNormalize';\n\nfunction cloneConfig(\n config: DeckMapDashboardConfigToolConfig,\n options?: PrepareAiDeckMapConfigOptions,\n): DeckMapDashboardPanelConfig {\n const normalized = prepareAiDeckMapConfig(config, options);\n return JSON.parse(JSON.stringify(normalized)) as DeckMapDashboardPanelConfig;\n}\n\n/**\n * Creates a dashboard-compatible Deck map panel from the native map config\n * used by AI tools and embeddable map surfaces.\n */\nexport function createDeckMapPanelFromNativeConfig(\n params: Pick<DeckMapConfigToolParams, 'title' | 'config'>,\n options?: PrepareAiDeckMapConfigOptions,\n) {\n return createDeckMapDashboardPanelConfig({\n title: params.title || 'Map',\n ...cloneConfig(params.config, options),\n });\n}\n\nexport function createDeckMapConfigTool(): Tool {\n return tool({\n description: `Deck map config: validates and returns a reusable native Deck JSON map configuration without requiring a dashboard artifact.\n\nUse when: a chat, agent, or artifact outside a dashboard needs a geospatial map config. Author the map using native Deck JSON: put layer classes in spec.layers[].@@type, bind layers to datasets through _sqlroomsBinding.dataset, and put tableName, tableName+transformSql, or sqlQuery sources in config.datasets. For data-driven colors, use color accessors such as getFillColor, getLineColor, getColor, getSourceColor, or getTargetColor with {\"@@function\":\"colorScale\", \"field\":\"...\", \"type\":\"...\", \"scheme\":\"...\", \"domain\":\"auto\"}. For categorical fields use scheme from: Tableau10, Set2, Category10, etc. For numeric fields use sequential schemes like Viridis.`,\n inputSchema: DeckMapConfigToolParameters,\n execute: async (params) => {\n try {\n const panel = createDeckMapPanelFromNativeConfig(params);\n return {\n llmResult: {\n success: true,\n details: `Created deck map config \"${panel.title}\".`,\n data: {\n kind: 'deck-map-config',\n title: panel.title,\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n config: panel.config,\n },\n },\n };\n } catch (error) {\n return {\n llmResult: {\n success: false,\n errorMessage:\n error instanceof Error ? error.message : String(error),\n },\n };\n }\n },\n });\n}\n\n/**\n * Creates AI tools for Deck.gl map configuration.\n * Returns tools for creating and configuring Deck.gl map panels.\n *\n * @returns Record mapping tool names to map configuration tools\n */\nexport function createDeckMapAiTools(): Record<string, Tool> {\n return {\n create_deck_map_config: createDeckMapConfigTool(),\n };\n}\n\n/**\n * Parameters for creating a Deck.gl map dashboard tool.\n * Provides adapters for dashboard and database operations.\n */\nexport type CreateDeckMapDashboardToolParams = {\n /** Dashboard adapter for adding and updating map panels */\n dashboardAdapter: DashboardAiAdapter;\n /** Database adapter for table validation */\n databaseAdapter: DatabaseAiAdapter;\n /** Host-injected catalogs to strip; omit for none — deck does not hardcode any. */\n stripCatalogNames?: readonly string[];\n};\n\n/**\n * Creates a tool for adding Deck.gl map panels to dashboards.\n * Supports creating new map panels or updating existing ones with native Deck JSON configs.\n *\n * @param params - Parameters containing dashboard and database adapters\n * @returns Tool instance for creating/updating Deck.gl map panels\n */\nexport function createDeckMapDashboardTool({\n dashboardAdapter,\n databaseAdapter,\n stripCatalogNames,\n}: CreateDeckMapDashboardToolParams): Tool {\n return tool({\n description: `Deck map panel: creates or updates an interactive geospatial map panel in a Mosaic dashboard from a native Deck JSON config.\n\nUse when: the user asks for a map in a dashboard. Author the map using native Deck JSON: choose layer classes with spec.layers[].@@type, bind layers to datasets through _sqlroomsBinding.dataset, and put tableName, tableName+transformSql, or sqlQuery sources in config.datasets. For data-driven colors, use color accessors such as getFillColor, getLineColor, getColor, getSourceColor, or getTargetColor with {\"@@function\":\"colorScale\", \"field\":\"...\", \"type\":\"...\", \"scheme\":\"...\", \"domain\":\"auto\"}. For categorical fields use scheme from: Tableau10, Set2, Category10, etc. For numeric fields use sequential schemes like Viridis.`,\n inputSchema: DeckMapDashboardToolParameters,\n execute: async (params) => {\n try {\n // Prepare/validate before mutating dashboard selection so a rejected\n // config does not switch the active table as a side effect.\n const panel = createDeckMapPanelFromNativeConfig(params, {\n resolveTable: (name) => databaseAdapter.findTable(name),\n stripCatalogNames,\n });\n const tableName =\n params.tableName ?? getFirstDatasetSourceTableName(panel.config);\n\n if (tableName) {\n ensureTable(databaseAdapter, tableName);\n }\n\n if (tableName) {\n await dashboardAdapter.setSelectedTable(tableName);\n }\n if (params.panelId) {\n ensurePanel(\n dashboardAdapter,\n params.panelId,\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n );\n\n await dashboardAdapter.updatePanel(params.panelId, {\n title: panel.title,\n config: panel.config,\n });\n\n return {\n llmResult: {\n success: true,\n details: `Updated map panel \"${panel.title}\".`,\n data: {\n panelId: params.panelId,\n title: panel.title,\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n config: panel.config,\n },\n },\n };\n }\n\n const panelId = await dashboardAdapter.addPanel(panel);\n\n return {\n llmResult: {\n success: true,\n details: `Created map panel \"${panel.title}\".`,\n data: {\n panelId,\n title: panel.title,\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n config: panel.config,\n },\n },\n };\n } catch (error) {\n return {\n llmResult: {\n success: false,\n errorMessage:\n error instanceof Error ? error.message : String(error),\n },\n };\n }\n },\n });\n}\n\nexport function createDeckMapDashboardAiTools(\n params: CreateDeckMapDashboardToolParams,\n): Record<string, Tool> {\n return {\n [MAP_TOOL_KEY]: createDeckMapDashboardTool(params),\n };\n}\n"]}
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"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","sourcesContent":["import {tool, type Tool} from 'ai';\nimport {z} from 'zod';\nimport {formatColorSchemePromptLists} from '@sqlrooms/color-scales/colorSchemeNames';\nimport {\n DashboardAiAdapter,\n MAP_TOOL_KEY,\n createDashboardAgentTool,\n createDashboardAiTools as createMosaicDashboardAiTools,\n type CreateDashboardAgentToolOptions,\n type CreateDashboardAiToolsOptions,\n ensureTable,\n ensurePanel,\n DatabaseAiAdapter,\n ExtraDashboardAiToolsFactory,\n ExtraDashboardAiToolsParams,\n MosaicDashboardStoreState,\n} from '@sqlrooms/mosaic';\nimport {\n createDeckMapDashboardPanelConfig,\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n type DeckMapDashboardPanelConfig,\n} from './dashboardConfig';\nimport {DECK_TABLE_DATASET_SOURCE_RELATION} from './datasets/tableDatasetSql';\nimport {\n getFirstDatasetSourceTableName,\n hasSqlOnlyDatasetSource,\n} from './datasetSourceUtils';\nimport {getDeckMapSharedAiContractRules} from './mapAiSharedInstructions';\nimport {prepareAiDeckMapConfig} from './aiNormalize';\nimport type {PrepareAiDeckMapConfigOptions} from './aiNormalize';\nimport {assertDeckMapResourceConfig} from './mapResourceAuthoring';\nimport {asDeckJsonMapConfig, withPreservedDeckMapStyle} from './mapConfig';\n\nexport {getFirstDatasetSourceTableName, hasSqlOnlyDatasetSource};\n\nconst COLOR_SCHEME_PROMPT_LISTS = formatColorSchemePromptLists();\n\nexport const DECK_MAP_AI_INSTRUCTIONS = `\nDeck map tools:\n- create_deck_map_config validates and returns a reusable native Deck JSON map config without requiring a dashboard artifact.\n- create_dashboard_map creates or updates an interactive map panel inside a dashboard from a native Deck JSON map config.\n- Use map tools when the user asks for a map, geospatial/spatial visualization, locations, longitude/latitude data, or geometry columns.\n- CONFIG MODE: Every map config must include a configMode field (\"basic\" or \"custom\") that determines how the map was authored and whether the UI settings panel is available.\n - \"basic\" (default): Use for straightforward requests — single layer, standard color scale, simple geometry binding. Stick ONLY to properties that the UI configurator supports: layer @@type, visibility, color scale (@@function colorScale), point radius (numeric getRadius with radiusUnits), line width (numeric getWidth with widthUnits), geometry/H3/arc column bindings, extrusion with a single elevation column (\"@@=columnName\" or {\"@@function\":\"scale\",\"field\":\"...\",\"type\":\"linear\",\"domain\":\"auto\",\"range\":[0,200]}). Do NOT use free-form string expressions (e.g. \"floors * 3\"), custom extensions, multiple layers, or advanced deck.gl props in basic mode. The user can fine-tune these maps through the settings panel.\n - \"custom\": Use when the request demands creative, complex, or advanced visualization — multiple layers, free-form data-driven accessors, custom color arrays, advanced deck.gl props (opacity, transitions, material, highlightColor, etc.), layer extensions, or any props not representable in the UI configurator. The UI settings panel will be disabled for custom configs; users edit via the JSON editor instead.\n - Decision rule: If the map can be fully expressed with a single layer + basic color scale + simple numeric radius/width (+ optional single elevation column), use \"basic\". Extruded GeoArrowColumnLayer / polygon maps with one elevation field must stay \"basic\" so the settings panel remains available. Use \"custom\" only when basic cannot express the request.\n- Author maps with config.spec.layers using Deck JSON layer classes in @@type, such as GeoArrowScatterplotLayer, GeoArrowHeatmapLayer, GeoArrowPolygonLayer, GeoArrowPathLayer, GeoArrowTripsLayer, GeoArrowArcLayer, GeoArrowH3HexagonLayer, or GeoJsonLayer. Always use the full GeoArrow-prefixed class name when choosing a GeoArrow layer (e.g. \"GeoArrowScatterplotLayer\", not \"ScatterplotLayer\") — unprefixed names are not registered. Prefer a typed GeoArrow* layer when the geometry type is known; use GeoJsonLayer for mixed or generic GeoJSON/WKB feature rendering with _sqlroomsBinding.\n${getDeckMapSharedAiContractRules()}\n- LAYER SELECTION: Choose the layer type based on the geometry type in the data.\n IMPORTANT: Only create a layer if the table contains data suitable for that layer type, or if you can transform the data into the required format with transformSql or a standalone sqlQuery. Do NOT create a layer if the data is clearly incompatible (e.g. do not create a path layer from point-only data without aggregation, do not create a polygon layer from point coordinates, do not create an arc layer without origin-destination pairs).\n - Point data (lon/lat coordinates, point geometry): GeoArrowScatterplotLayer (Point layer), GeoArrowHeatmapLayer, GeoArrowColumnLayer. Requires lon/lat columns (via ST_Point transformSql) or a Point geometry column — follow the shared Point-position rules above.\n - Polygon data (building footprints, boundaries, areas, parcels, zones): GeoArrowPolygonLayer for uniform Polygon columns. Use GeoJsonLayer for WKB/WKT MultiPolygon columns so separate polygon parts retain their nesting.\n - Line data (roads, routes, paths, rivers): GeoArrowPathLayer. Requires LineString geometry (or a single-part MultiLineString). Multi-part MultiLineString cannot be rendered as one path — explode/merge with ST_Dump / ST_LineMerge first. If the table has one row per waypoint (path_id/route_id + order/sequence + lat/lon), aggregate with transformSql: \"SELECT path_id, label, ST_AsWKB(ST_MakeLine(LIST(ST_Point(lon, lat) ORDER BY waypoint_order))) AS geom FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} GROUP BY path_id, label\". Set geometryColumn to \"geom\" and geometryEncodingHint to \"wkb\". If linestring geom already exists, use it directly (or SELECT * EXCLUDE (geom), ST_AsWKB(geom) AS geom ... WHERE ST_GeometryType(geom) = 'LINESTRING').\n - Animated trip data (routes with timestamps): GeoArrowTripsLayer (see shared trips-vs-arc rule). One row per trip: LineString geom + timestamps list (same order/length as vertices).\n (1) Waypoint rows (trip_id/path_id + lat/lon + order/time): GROUP BY trip id. Example: \"SELECT trip_id, ANY_VALUE(label) AS label, ST_AsWKB(ST_MakeLine(LIST(ST_Point(lon, lat) ORDER BY waypoint_order))) AS geom, LIST(timestamp ORDER BY waypoint_order) AS timestamps FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} GROUP BY trip_id\". Keep attrs with ANY_VALUE(col). Use ST_MakeLine(LIST(...)) only — never ST_MakeLine(ST_Point(...) ORDER BY ...); always GROUP BY the trip id.\n (2) OD pairs already one row per trip: no GROUP BY — \"SELECT trip_id, ST_AsWKB(ST_MakeLine([ST_Point(pickup_lon, pickup_lat), ST_Point(dropoff_lon, dropoff_lat)])) AS geom, [0.0, 1.0] AS timestamps FROM ${DECK_TABLE_DATASET_SOURCE_RELATION}\" (prefer [0.0, duration] when available).\n In both cases set geometryColumn to \"geom\", geometryEncodingHint to \"wkb\", and _sqlroomsBinding.timestampColumn to \"timestamps\".\n - Arc data (origin-destination pairs): GeoArrowArcLayer for arcs/connections/flows/OD links only (see shared arc-binding rule). Example transformSql: \"SELECT *, ST_AsWKB(ST_Point(source_lon, source_lat)) AS source_geom, ST_AsWKB(ST_Point(target_lon, target_lat)) AS target_geom FROM ${DECK_TABLE_DATASET_SOURCE_RELATION}\". Flat lines: \"getHeight\": 0. For H3 OD pairs use h3_cell_to_lng/lat inside ST_Point (not h3_latlng).\n - H3 hexagon data: GeoArrowH3HexagonLayer (see shared H3 rule). Include fitToData {\"dataset\":\"datasetId\"}. Valid H3 helpers: h3_cell_to_lat/lng/latlng — not h3_latlng/h3_to_lat.\n- CRITICAL geometryColumn rule: The geometryColumn field (in datasets[id].geometryColumn, _sqlroomsBinding.geometryColumn, and fitToData.geometryColumn) MUST match the exact column alias that produces the WKB geometry in the final query output — typically the \"AS geom\" alias in ST_AsWKB(...) AS geom. It must NEVER be set to a GROUP BY key, an ID column, or any other non-geometry column. For example, if the transformSql is \"SELECT path_id, ST_AsWKB(ST_MakeLine(...)) AS geom ... GROUP BY path_id\", geometryColumn must be \"geom\" (the geometry output), NOT \"path_id\" (the grouping key). Setting geometryColumn to a non-geometry column will cause the layer to fail silently.\n- CRITICAL: The transformSql and sqlQuery fields must contain ONLY a single SELECT statement. NEVER put INSTALL, LOAD, CREATE, or other DDL/meta-commands in dataset SQL — they will fail because dataset SQL is wrapped in a subquery at runtime. Extensions like h3 and spatial are pre-loaded at startup.\n - GeoJSON files typically contain polygon or multipolygon features; use polygon layers (or follow shared Point/mixed rules when the user asks for points/mixed rendering).\n- RADIUS AND WIDTH: For GeoArrowScatterplotLayer (Point layer) use numeric getRadius with radiusUnits: \"pixels\" (typically 2–6). Never use string expressions like \"field * 500\" in basic mode — they bypass pixel clamping. Data-driven size: \"@@=columnName\" only in configMode \"custom\", with radiusUnits meters so radiusMaxPixels can cap. For GeoArrowColumnLayer use \"radius\" in meters (not getRadius/radiusUnits), typically 20–200. Always set \"extruded\": true when using getElevation. For Arc/Path/Trips use numeric getWidth with widthUnits: \"pixels\" (typically 1–3).\n- ARC vs LINE: GeoArrowArcLayer renders curved 3D arcs by default. If the user asks for \"lines\" or \"straight connections\" between origin-destination pairs (not arcs), set \"getHeight\": 0 on the layer to render flat straight lines. Use arcs for flight routes or connections where the curve adds clarity; use flat lines for direct relationships, edges, or when the user explicitly requests lines.\n- ELEVATION: For extruded layers set \"extruded\": true. Prefer getElevation {\"@@function\":\"scale\",\"field\":\"...\",\"type\":\"linear\",\"domain\":\"auto\",\"range\":[0,200]} (basic-mode friendly) or \"@@=columnName\". elevationScale multiplies raw field meters — keep max visual height moderate (~hundreds of meters). Do NOT use negative elevation. For polygon building footprints with GeoArrowColumnLayer, transformSql should produce points via the shared centroid rule. CRITICAL: Extruded ColumnLayer / polygon maps need a pitched camera — set spec.initialViewState with pitch around 45–60 (and optional bearing). Top-down pitch 0 makes columns look like flat disks and appear \"missing\".\n- Bind layers to datasets with _sqlroomsBinding.dataset and put tableName, tableName+transformSql, or sqlQuery sources in config.datasets.\n- Use source.tableName for direct table-backed datasets. Use source.tableName plus source.transformSql when the map needs generated geometry or aggregation but should still follow the dashboard selected table. transformSql must read from ${DECK_TABLE_DATASET_SOURCE_RELATION}, not from the authored table name.\n- Use source.sqlQuery only for a standalone literal query that should remain pinned to the authored SQL. Dashboard selected table replacement applies only to structured tableName sources, not literal sqlQuery sources.\n- IMPORTANT: Always pass tableName in the create_dashboard_map tool params (the top-level tableName field). Use the table currently selected in the dashboard (dashboard.selectedTable from list_dashboard_panels). At runtime, the dashboard's selected table overrides structured source.tableName values — this param seeds or changes that selection.\n- IMPORTANT: If you are creating a structured table-backed map layer for a table that is NOT the currently selected dashboard table, you MUST switch the dashboard's selected table to that dataset BEFORE or WHEN calling create_dashboard_map (pass the correct tableName). Structured table-backed map panels resolve data from the dashboard's active table — if you don't switch it, the layer will query the wrong table and fail.\n- IMPORTANT: When referencing tables in tableName or sqlQuery, use ONLY the bare table name (e.g. \"my_table\") or schema-qualified name (e.g. \"main.my_table\"). NEVER include the database/catalog prefix (e.g. do NOT use \"sqlrooms-cli.main.my_table\") — the catalog does not exist in the query execution context.\n- IMPORTANT: For point data with longitude/latitude columns that should follow dashboard table switching, use source.tableName plus source.transformSql to create a geometry column, for example: \"SELECT *, ST_AsWKB(ST_Point(\\\\\"Longitude\\\\\", \\\\\"Latitude\\\\\")) AS \\\\\"__sqlrooms_geom\\\\\" FROM ${DECK_TABLE_DATASET_SOURCE_RELATION} WHERE \\\\\"Longitude\\\\\" IS NOT NULL AND \\\\\"Latitude\\\\\" IS NOT NULL\". Set geometryColumn to the same name used in the AS clause (e.g. \"__sqlrooms_geom\") and geometryEncodingHint to \"wkb\".\n- IMPORTANT: When providing fitToData, it MUST be a flat object (NOT nested by dataset ID). Include either longitudeColumn+latitudeColumn (for point data with separate coordinate columns) OR geometryColumn (for data with a WKB geometry column like GeoJSON). For H3 hexagon layers, just specify the dataset: \"fitToData\": {\"dataset\": \"datasetId\"} — the H3 column is auto-detected from the layer binding. For GeoJSON/spatial files with a \"geom\" column, use: \"fitToData\": {\"dataset\": \"datasetId\", \"geometryColumn\": \"geom\"}. For point data use: \"fitToData\": {\"dataset\": \"datasetId\", \"longitudeColumn\": \"lon\", \"latitudeColumn\": \"lat\"}. NEVER nest fitToData as {\"datasetId\": {...}} — always use a flat object with \"dataset\" as a string field.\n- IMPORTANT: For GeoJSON or spatial files that already have a native geometry column (e.g. \"geometry\", \"geom\"), use the table directly with source.tableName (no sqlQuery needed), set the dataset's geometryColumn to \"geom\", set geometryEncodingHint to \"wkb\", and use fitToData with geometryColumn: {\"dataset\": \"datasetId\", \"geometryColumn\": \"geom\"}.\n- IMPORTANT: When a GeoJSON file (.geojson) is loaded as a table, DuckDB uses ST_Read to produce a table with a WKB \"geom\" column and all feature properties as columns. Use source.tableName, set geometryColumn to \"geom\" and geometryEncodingHint to \"wkb\". Use \"fitToData\": {\"dataset\": \"datasetId\", \"geometryColumn\": \"geom\"} to zoom to the data extent.\n- For data-driven color, use {\"@@function\":\"colorScale\", \"field\":\"...\", \"type\":\"sequential\"|\"diverging\"|\"quantize\"|\"quantile\"|\"categorical\", \"scheme\":\"...\", \"domain\":\"auto\"} on getFillColor / getLineColor / getColor / getSourceColor / getTargetColor. Key is \"@@function\" (not \"@@type\"); column goes in \"field\" (not \"column\"). Exact scheme names: ${COLOR_SCHEME_PROMPT_LISTS}. \"field\" must exist in the FINAL query output after any GROUP BY.\n- COLOR SCALE PREFERENCE: Prefer colorScale over flat fill when a useful varying column exists — numeric → sequential/quantile (quantile if skewed); categorical/string → categorical. A numeric column is useful only when min < max (not all zeros / constant); otherwise use flat fill. If the user explicitly names a column for color, honor that even when flat. Flat fill also when the user asks for one color. \"field\" must be the exact schema column name (case-sensitive; \"Magnitude\" not \"mag\"). IMPORTANT: Viridis/Plasma/Inferno/Turbo/Cividis/Magma require type \"sequential\" (not quantile/quantize). Quantile/quantize schemes must be ColorBrewer ramps such as YlOrRd, Blues, Greens, RdYlBu.\n- IMPORTANT: Enabling a color scale means adding a {\"@@function\":\"colorScale\", ...} accessor to a compatible layer color property. The top-level showLegends field only controls whether already-defined color scale legends are visible; showLegends by itself does NOT create or enable data-driven color.\n- Map panels default to a 100000-row runtime data limit; use config.dataPolicy.maxRows only when the map genuinely needs a panel-specific limit.\n- Create maps with a SINGLE layer unless the user explicitly asks for multiple layers. If you think multiple layers would better serve the user's request, ask the user for confirmation before adding them.\n- IMPORTANT: Browsers limit the number of active WebGL contexts (typically 8–16 per page). Each map panel uses one context. Do NOT create more than 4–5 map panels in a single dashboard — exceeding the limit causes older maps to lose their rendering context and show errors. If the user asks for many datasets, prefer combining compatible layers into fewer maps rather than creating one map per dataset.\n- After calling create_dashboard_map, call list_dashboard_panels before your final response and check the map panel issue. If it has a render-error, repair the map config in place instead of saying the map is complete.\n- IMPORTANT: Dashboard map tools replace the full panel config — always include datasets and layers on updates. Omitting datasets is only valid for document sparse patches that merge with durable state.\n- SWITCHING LAYER TYPE: On type switch/replace, send only the new layer (replaceLayers: true for merge patches; full desired layers list for dashboard updates). Do not leave the old layer as visible: false.\n`;\n\nfunction createDeckMapDashboardExtraTools(\n extraTools?: ExtraDashboardAiToolsFactory,\n prepareOptions?: Pick<PrepareAiDeckMapConfigOptions, 'stripCatalogNames'>,\n) {\n return (params: ExtraDashboardAiToolsParams) => ({\n ...createDeckMapDashboardAiTools({\n ...params,\n stripCatalogNames: prepareOptions?.stripCatalogNames,\n }),\n ...(extraTools?.(params) ?? {}),\n });\n}\n\n/**\n * Returns AI instructions for dashboards with Deck.gl map support.\n * Provides guidance on when and how to use map visualizations.\n *\n * @returns Instructions string for AI agents\n */\nexport function getDashboardWithDeckMapAiInstructions() {\n return `${DECK_MAP_AI_INSTRUCTIONS.trim()}`;\n}\n\n/**\n * Creates dashboard AI tools with built-in Deck.gl map support.\n * Extends standard dashboard tools with map visualization capabilities.\n *\n * @param options - Dashboard AI tools configuration options\n * @returns Record mapping tool names to tool instances, including map tools\n */\nexport type CreateDashboardWithDeckMapAiToolsOptions =\n CreateDashboardAiToolsOptions & {\n /** Host-injected catalogs to strip; omit for none — deck does not hardcode any. */\n stripCatalogNames?: readonly string[];\n };\n\nexport function createDashboardWithDeckMapAiTools(\n options: CreateDashboardWithDeckMapAiToolsOptions,\n): Record<string, Tool> {\n const {stripCatalogNames, extraTools, ...rest} = options;\n return createMosaicDashboardAiTools({\n ...rest,\n extraTools: createDeckMapDashboardExtraTools(extraTools, {\n stripCatalogNames,\n }),\n });\n}\n\n/**\n * Creates a dashboard agent tool with built-in Deck.gl map support.\n * Extends the standard dashboard agent with map creation capabilities.\n *\n * @template TState - Store state type extending MosaicDashboardStoreState\n * @param options - Dashboard agent configuration options\n * @returns Dashboard agent tool with map support\n */\nexport type CreateDashboardAgentToolWithDeckMapsOptions<\n TState extends MosaicDashboardStoreState,\n> = CreateDashboardAgentToolOptions<TState> & {\n stripCatalogNames?: readonly string[];\n};\n\nexport function createDashboardAgentToolWithDeckMaps<\n TState extends MosaicDashboardStoreState,\n>(options: CreateDashboardAgentToolWithDeckMapsOptions<TState>): Tool {\n const {stripCatalogNames, extraTools, ...rest} = options;\n return createDashboardAgentTool({\n ...rest,\n additionalInstructions: [\n options.additionalInstructions,\n DECK_MAP_AI_INSTRUCTIONS.trim(),\n ]\n .filter(Boolean)\n .join('\\n\\n'),\n extraTools: createDeckMapDashboardExtraTools(extraTools, {\n stripCatalogNames,\n }),\n });\n}\n\nconst DeckMapLayerBindingConfig = z.looseObject({\n dataset: z.string().optional(),\n geometryColumn: z.string().optional(),\n geometryEncodingHint: z.enum(['geoarrow', 'wkb', 'wkt']).optional(),\n sourceGeometryColumn: z.string().optional(),\n targetGeometryColumn: z.string().optional(),\n timestampColumn: z.string().optional(),\n hexagonColumn: z.string().optional(),\n});\n\nconst DeckMapLayerSpec = z.looseObject({\n '@@type': z.string().optional(),\n id: z.string().optional(),\n _sqlroomsBinding: DeckMapLayerBindingConfig.optional(),\n});\n\nconst DeckMapSpec = z.looseObject({\n initialViewState: z.record(z.string(), z.unknown()).optional(),\n viewState: z.record(z.string(), z.unknown()).optional(),\n controller: z.unknown().optional(),\n layers: z.array(DeckMapLayerSpec).optional(),\n});\n\nconst DeckMapDatasetSource = z.looseObject({\n tableName: z.string().optional(),\n transformSql: z.string().optional(),\n sqlQuery: z.string().optional(),\n});\n\nconst DeckMapDatasetConfig = z.looseObject({\n source: DeckMapDatasetSource.optional(),\n geometryColumn: z.string().optional(),\n geometryEncodingHint: z.enum(['geoarrow', 'wkb', 'wkt']).optional(),\n});\n\nconst DeckMapDataPolicyConfig = z.looseObject({\n disabled: z.boolean().optional(),\n maxRows: z.number().int().min(1).optional(),\n reason: z.string().optional(),\n});\n\nexport const DeckMapDashboardConfigParameter = z.looseObject({\n spec: DeckMapSpec.describe(\n 'Deck JSON map spec as an object. Use spec.layers[].@@type for layer classes such as GeoArrowScatterplotLayer (Point layer), GeoArrowHeatmapLayer, GeoArrowPolygonLayer, GeoArrowPathLayer, or GeoArrowArcLayer.',\n ),\n datasets: z\n .record(z.string(), DeckMapDatasetConfig)\n .describe(\n 'Datasets keyed by dataset id. Layers bind to these ids through _sqlroomsBinding.dataset. Each dataset source may use tableName, tableName+transformSql, or sqlQuery.',\n ),\n configMode: z\n .enum(['basic', 'custom'])\n .optional()\n .describe(\n 'Config authoring mode. Use \"basic\" (default) for straightforward single-layer maps that the user can tweak via the UI settings panel. Use \"custom\" for complex, multi-layer, or creative maps that use advanced deck.gl props beyond what the UI configurator supports — the settings panel will be disabled for custom configs.',\n ),\n mapStyle: z.string().optional(),\n mapProps: z.record(z.string(), z.unknown()).optional(),\n showLegends: z\n .boolean()\n .optional()\n .describe(\n 'Whether to show color scale legends on the map. Defaults to true; omit or set true unless the user explicitly asks to hide legends.',\n ),\n interaction: z.record(z.string(), z.unknown()).optional(),\n fitToData: z\n .object({\n dataset: z.string().describe('Dataset id to compute bounds from.'),\n longitudeColumn: z\n .string()\n .optional()\n .describe('Longitude column name for point data.'),\n latitudeColumn: z\n .string()\n .optional()\n .describe('Latitude column name for point data.'),\n geometryColumn: z\n .string()\n .optional()\n .describe('WKB geometry column name for computing bounds.'),\n geometryColumns: z\n .array(z.string())\n .optional()\n .describe(\n 'Multiple WKB geometry columns whose extents are combined (e.g. arc source + target). Prefer omitting this — for GeoArrowArcLayer it is inferred from _sqlroomsBinding.',\n ),\n h3Column: z\n .string()\n .optional()\n .describe('H3 hex index column for computing bounds.'),\n padding: z.number().optional(),\n maxZoom: z.number().optional(),\n })\n .optional()\n .describe(\n 'Fit map view to data bounds. Provide dataset plus either geometryColumn (for WKB geometry) or longitudeColumn+latitudeColumn (for separate coordinate columns). For arc layers, just {\"dataset\": \"datasetId\"} is enough — source and target geometry columns are inferred from the layer binding. Example: {\"dataset\": \"myDataset\", \"geometryColumn\": \"geom\"}',\n ),\n dataPolicy: DeckMapDataPolicyConfig.optional().describe(\n 'Optional per-map runtime data policy. Maps default to 100000 rows; set maxRows for a panel-specific override or disabled=true to bypass row-count validation.',\n ),\n settingsOpen: z.boolean().optional(),\n});\n\nexport type DeckMapDashboardConfigToolConfig = z.infer<\n typeof DeckMapDashboardConfigParameter\n>;\n\nexport const DeckMapConfigToolParameters = z.object({\n title: z.string().optional().default('Map').describe('Map title.'),\n config: DeckMapDashboardConfigParameter.describe(\n 'Native Deck JSON dashboard map config. This is the canonical map representation.',\n ),\n reasoning: z\n .string()\n .describe('Brief rationale for creating the map config.'),\n});\n\nexport type DeckMapConfigToolParams = z.infer<\n typeof DeckMapConfigToolParameters\n>;\n\nexport const DeckMapDashboardToolParameters =\n DeckMapConfigToolParameters.extend({\n tableName: z\n .string()\n .optional()\n .describe(\n 'Optional table name used only to select/resolve the target dashboard table. Data sources still come from config.datasets.',\n ),\n panelId: z\n .string()\n .optional()\n .describe(\n 'Optional panel ID. If provided, updates the existing map panel instead of creating a new one.',\n ),\n reasoning: z\n .string()\n .describe('Brief rationale for creating the map panel.'),\n });\n\nexport type DeckMapDashboardToolParams = z.infer<\n typeof DeckMapDashboardToolParameters\n>;\n\nexport {\n normalizeAiDeckMapConfig,\n prepareAiDeckMapConfig,\n validateAndFixColorScaleFields,\n} from './aiNormalize';\n\nfunction cloneConfig(\n config: DeckMapDashboardConfigToolConfig,\n options?: PrepareAiDeckMapConfigOptions,\n): DeckMapDashboardPanelConfig {\n const normalized = prepareAiDeckMapConfig(config, options);\n const cloned = JSON.parse(\n JSON.stringify(normalized),\n ) as DeckMapDashboardPanelConfig;\n assertDeckMapResourceConfig(cloned);\n return cloned;\n}\n\n/**\n * Creates a dashboard-compatible Deck map panel from the native map config\n * used by AI tools and embeddable map surfaces.\n */\nexport function createDeckMapPanelFromNativeConfig(\n params: Pick<DeckMapConfigToolParams, 'title' | 'config'>,\n options?: PrepareAiDeckMapConfigOptions,\n) {\n const config = cloneConfig(params.config, options);\n return createDeckMapDashboardPanelConfig({\n title: params.title || 'Map',\n ...config,\n });\n}\n\nexport function createDeckMapConfigTool(): Tool {\n return tool({\n description: `Deck map config: validates and returns a reusable native Deck JSON map configuration without requiring a dashboard artifact.\n\nUse when: a chat, agent, or artifact outside a dashboard needs a geospatial map config. Author the map using native Deck JSON: put layer classes in spec.layers[].@@type, bind layers to datasets through _sqlroomsBinding.dataset, and put tableName, tableName+transformSql, or sqlQuery sources in config.datasets. For data-driven colors, use color accessors such as getFillColor, getLineColor, getColor, getSourceColor, or getTargetColor with {\"@@function\":\"colorScale\", \"field\":\"...\", \"type\":\"...\", \"scheme\":\"...\", \"domain\":\"auto\"}. For categorical fields use scheme from: Tableau10, Set2, Category10, etc. For numeric fields use sequential schemes like Viridis.`,\n inputSchema: DeckMapConfigToolParameters,\n execute: async (params) => {\n try {\n const panel = createDeckMapPanelFromNativeConfig(params);\n return {\n llmResult: {\n success: true,\n details: `Created deck map config \"${panel.title}\".`,\n data: {\n kind: 'deck-map-config',\n title: panel.title,\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n config: panel.config,\n },\n },\n };\n } catch (error) {\n return {\n llmResult: {\n success: false,\n errorMessage:\n error instanceof Error ? error.message : String(error),\n },\n };\n }\n },\n });\n}\n\n/**\n * Creates AI tools for Deck.gl map configuration.\n * Returns tools for creating and configuring Deck.gl map panels.\n *\n * @returns Record mapping tool names to map configuration tools\n */\nexport function createDeckMapAiTools(): Record<string, Tool> {\n return {\n create_deck_map_config: createDeckMapConfigTool(),\n };\n}\n\n/**\n * Parameters for creating a Deck.gl map dashboard tool.\n * Provides adapters for dashboard and database operations.\n */\nexport type CreateDeckMapDashboardToolParams = {\n /** Dashboard adapter for adding and updating map panels */\n dashboardAdapter: DashboardAiAdapter;\n /** Database adapter for table validation */\n databaseAdapter: DatabaseAiAdapter;\n /** Host-injected catalogs to strip; omit for none — deck does not hardcode any. */\n stripCatalogNames?: readonly string[];\n};\n\n/**\n * Creates a tool for adding Deck.gl map panels to dashboards.\n * Supports creating new map panels or updating existing ones with native Deck JSON configs.\n *\n * @param params - Parameters containing dashboard and database adapters\n * @returns Tool instance for creating/updating Deck.gl map panels\n */\nexport function createDeckMapDashboardTool({\n dashboardAdapter,\n databaseAdapter,\n stripCatalogNames,\n}: CreateDeckMapDashboardToolParams): Tool {\n return tool({\n description: `Deck map panel: creates or updates an interactive geospatial map panel in a Mosaic dashboard from a native Deck JSON config.\n\nUse when: the user asks for a map in a dashboard. Author the map using native Deck JSON: choose layer classes with spec.layers[].@@type, bind layers to datasets through _sqlroomsBinding.dataset, and put tableName, tableName+transformSql, or sqlQuery sources in config.datasets. For data-driven colors, use color accessors such as getFillColor, getLineColor, getColor, getSourceColor, or getTargetColor with {\"@@function\":\"colorScale\", \"field\":\"...\", \"type\":\"...\", \"scheme\":\"...\", \"domain\":\"auto\"}. For categorical fields use scheme from: Tableau10, Set2, Category10, etc. For numeric fields use sequential schemes like Viridis.`,\n inputSchema: DeckMapDashboardToolParameters,\n execute: async (params) => {\n try {\n // Prepare/validate before mutating dashboard selection so a rejected\n // config does not switch the active table as a side effect.\n const config = cloneConfig(params.config, {\n resolveTable: (name) => databaseAdapter.findTable(name),\n stripCatalogNames,\n });\n const title = params.title || 'Map';\n const tableName =\n params.tableName ?? getFirstDatasetSourceTableName(config);\n\n if (tableName) {\n ensureTable(databaseAdapter, tableName);\n }\n\n if (tableName) {\n await dashboardAdapter.setSelectedTable(tableName);\n }\n if (params.panelId) {\n const existingPanel = ensurePanel(\n dashboardAdapter,\n params.panelId,\n DECK_MAP_DASHBOARD_PANEL_TYPE,\n );\n const updatedConfig: Record<string, unknown> =\n withPreservedDeckMapStyle(\n config,\n asDeckJsonMapConfig(existingPanel.config),\n );\n\n await dashboardAdapter.updatePanel(params.panelId, {\n title,\n config: updatedConfig,\n });\n\n return {\n llmResult: {\n success: true,\n details: `Updated map panel \"${title}\".`,\n data: {\n panelId: params.panelId,\n title,\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n config: updatedConfig,\n },\n },\n };\n }\n\n const panel = createDeckMapDashboardPanelConfig({title, ...config});\n const panelId = await dashboardAdapter.addPanel(panel);\n\n return {\n llmResult: {\n success: true,\n details: `Created map panel \"${panel.title}\".`,\n data: {\n panelId,\n title: panel.title,\n type: DECK_MAP_DASHBOARD_PANEL_TYPE,\n config: panel.config,\n },\n },\n };\n } catch (error) {\n return {\n llmResult: {\n success: false,\n errorMessage:\n error instanceof Error ? error.message : String(error),\n },\n };\n }\n },\n });\n}\n\nexport function createDeckMapDashboardAiTools(\n params: CreateDeckMapDashboardToolParams,\n): Record<string, Tool> {\n return {\n [MAP_TOOL_KEY]: createDeckMapDashboardTool(params),\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"aiNormalize.d.ts","sourceRoot":"","sources":["../src/aiNormalize.ts"],"names":[],"mappings":"AA8kBA;;;GAGG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxE,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,+BAA+B,GACxC,CAAC,CAcH;AAUD,MAAM,MAAM,sBAAsB,GAAG,CACnC,SAAS,EAAE,MAAM,KACd;IAAC,OAAO,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,EAAE,CAAA;CAAC,GAAG,SAAS,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,CAAC,SAAS;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAC,EAC9D,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,sBAAsB,GAAG,CAAC,CAmIpD;AAED;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG,+BAA+B,GAAG;IAC5E,YAAY,CAAC,EAAE,sBAAsB,CAAC;CACvC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtE,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,6BAA6B,GACtC,CAAC,CAOH"}
1
+ {"version":3,"file":"aiNormalize.d.ts","sourceRoot":"","sources":["../src/aiNormalize.ts"],"names":[],"mappings":"AA+kBA;;;GAGG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxE,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,+BAA+B,GACxC,CAAC,CAcH;AAUD,MAAM,MAAM,sBAAsB,GAAG,CACnC,SAAS,EAAE,MAAM,KACd;IAAC,OAAO,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,EAAE,CAAA;CAAC,GAAG,SAAS,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,CAAC,SAAS;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAC,EAC9D,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,sBAAsB,GAAG,CAAC,CAmIpD;AAED;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG,+BAA+B,GAAG;IAC5E,YAAY,CAAC,EAAE,sBAAsB,CAAC;CACvC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtE,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,6BAA6B,GACtC,CAAC,CAOH"}
@@ -177,7 +177,8 @@ function normalizeAiMapConfigLayers(config) {
177
177
  }
178
178
  // AI-only strip: UI may keep colorRange; do not reject in the resource validator.
179
179
  if (l['@@type'] === 'GeoArrowHeatmapLayer' && 'colorRange' in l) {
180
- const { colorRange: _cr, ...rest } = l;
180
+ const rest = { ...l };
181
+ delete rest.colorRange;
181
182
  l = rest;
182
183
  layerChanged = true;
183
184
  }