Skip to content

feat: Deck map ai tool - #654

Merged
ilyabo merged 19 commits into
mainfrom
feat--Deck-map-ai-tool
May 22, 2026
Merged

ilyabo merged 19 commits into
mainfrom
feat--Deck-map-ai-tool

Conversation

@ilyabo

@ilyabo ilyabo commented May 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • AI-powered map panel generation with improved coordinate/geometry detection and dashboard creation/updating.
    • Per-panel data-policy overrides for maps and charts (max rows/disable/reason) and a “Max rows” setting in map UI.
    • Host-app extensible dashboard AI tools and a standardized map tool key for registering map tools.
  • Refactor

    • Map settings UI reorganized for layer selection, type, and color-scale management; panel config generation centralized.
  • Tests

    • Expanded unit tests for map AI tools, panel creation/update, color-scale behavior, and layer utilities.
  • Documentation

    • README updated to document host tools and map tool registration.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 21, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Deck map AI tools and schemas, refactors map-config and map-layer utilities, wires host-injected map tools into Mosaic AI (MAP_TOOL_KEY), propagates per-panel dataPolicy and runtime-issue plumbing into map rendering, updates CLI/store/UI to use the new utilities, expands exports and package deps, and adds tests and docs.

Changes

Deck map dashboard AI tool and host tool injection

Layer / File(s) Summary
Map configuration utilities and builder
packages/deck/src/mapConfigUtils.ts
Adds deck-map types, lon/lat and geometry detection, SQL quoting/normalization helpers, createDeckMapDashboardConfigForTable, panel wrapper, and updated regenerateMapConfigForTable.
Map-layer config & color-scale helpers
packages/deck/src/mapLayerConfigUtils.ts, packages/deck/src/json/colorScaleFunction.ts
Introduces layer/type constants, dataset binding helpers, geometry-column helpers, immutable layer update APIs, color-scale read/write/clear, createDeckMapLayerColorScale defaults, and expands color-scale detection to more accessor props.
Deck AI schemas and tools
packages/deck/src/ai.ts, packages/deck/package.json
Adds Zod schemas for native Deck JSON and tool parameters, implements createDeckMapConfigTool and createDeckMapDashboardTool, registers tools (createDeckMapAiTools/createDeckMapDashboardAiTools), and adds an ai dependency.
Dashboard rendering & runtime dataPolicy
packages/deck/src/dashboard.tsx, packages/deck/src/dashboardConfig.ts
Replaces local table→map helpers with mapConfigUtils, adds runtime-issue reporting/clearing and DeckMapRuntimeIssuePanel, computes/resolves per-panel dataPolicy, and threads it into dataset client/useMosaicClient.
MapSettings UI
packages/deck/src/MapSettings.tsx
Refactors layer selection and color-scale editing, adds scheme options, centralized config application, and a "Max rows" input that persists dataPolicy.maxRows.
Mosaic AI host-tool injection & MAP_TOOL_KEY
packages/mosaic/src/ai.ts, packages/mosaic/__tests__/dashboard-ai.test.ts
Adds extraTools(deps) hook, validates host-tool key collisions, merges host tools into the AI tool map, exports MAP_TOOL_KEY, updates dashboard instructions, and derives maxDataPoints from adapter hook when present.
Chart data-policy support
packages/mosaic/src/chart-runtime.ts, packages/mosaic/src/chart-types/*
Adds ChartDataPolicyOverride and resolveChartDataPolicy, introduces ChartDataPolicyOverrideConfig schema, and extends chart-type schemas to accept optional dataPolicy.
CLI & store wiring, barrel exports, README
apps/sqlrooms-cli-ui/src/*, packages/deck/src/index.ts, packages/mosaic/README.md
Composes Deck map AI instructions into CLI AI instructions, wires extraTools into the dashboard agent, imports deck exports into the store (removing local duplicates), expands deck barrel exports, documents MAP_TOOL_KEY and extraTools rules, and updates package deps.
Tests
packages/deck/__tests__/*, packages/mosaic/__tests__/*
Adds tests for deck-map AI tools, dashboard tool registration and create/update flows, mapConfigForTable behaviors (ST_Point SQL, semicolon wrapping), map-layer utilities (color-scale and geometry column), and mosaic AI instruction/collision behavior.

Estimated code review effort: 🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • dmitriy-kostianetskiy

"🐰 I patched the map, I tuned each scale,
From ST_Point arcs to dashboard tale.
Host tools invited, panels take flight,
Geometries glow on the dark of night."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: Deck map ai tool' directly describes the main feature addition: implementing AI tooling for Deck map functionality, which is the central change across this large changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat--Deck-map-ai-tool

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/mosaic/src/ai.ts (2)

172-172: 💤 Low value

Implicit naming contract on create_dashboard_map.

The prompt text hardcodes the expected tool name create_dashboard_map, but extraTools lets hosts register tools under any key. If a host names its map tool differently, these instructions become misleading. Consider documenting the expected key in the extraTools JSDoc, or exposing a small constant/registration helper so the prompt and the tool key stay in sync.

Also applies to: 197-197

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mosaic/src/ai.ts` at line 172, The prompt text hardcodes the tool
name create_dashboard_map while hosts can register tools under any key via
extraTools; update the code to avoid the implicit naming contract by introducing
a single exported constant (e.g., MAP_TOOL_KEY) or a small registration helper
(e.g., registerMapTool) and reference that symbol in the prompt text instead of
the literal string, and add JSDoc on extraTools to document the expected
key/registration helper so prompt and tool key stay in sync (also apply the same
change for the other occurrence noted around line 197).

485-491: 💤 Low value

Host tools can silently override built-in tools.

...hostTools is spread after the built-in entries, so a host returning a key like create_dashboard_artifact or any chart tool name will shadow the Mosaic-owned implementation without warning. If override is intentional, fine; otherwise consider spreading hostTools first (so built-ins win), or detecting collisions and warning. Worth a quick decision since this is a public extension point.

Optional defensive variant
-  const hostTools = extraTools?.(deps) ?? {};
+  const hostTools = extraTools?.(deps) ?? {};
+  if (process.env.NODE_ENV !== 'production') {
+    for (const key of Object.keys(hostTools)) {
+      if (key in builtInToolKeys) {
+        console.warn(`[mosaic] extraTools "${key}" overrides a built-in dashboard tool.`);
+      }
+    }
+  }

Also applies to: 524-524

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mosaic/src/ai.ts` around lines 485 - 491, Host-provided tools
(hostTools from extraTools) are currently spread after built-in entries in
CreateDashboardAiToolsOptions (in the function creating chartTools and
hostTools), allowing silent overrides of built-in tools like
create_dashboard_artifact or any chart tool; change the merge order or add
collision detection: either spread hostTools before the built-ins so built-ins
win, or, inside the function that builds the final tool map (where
createChartTools, resolvedChartTypes, hostTools and chartTools are combined),
iterate hostTools keys and check for existing keys in chartTools/built-ins and
log/warn or throw if a collision is found (refer to hostTools, createChartTools,
createDashboardToolDeps, createDefaultChartTypes, and the built-in key names
such as create_dashboard_artifact) and choose the desired behavior (prevent
override by default or allow with explicit warning).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/deck/src/mapConfigUtils.ts`:
- Around line 126-128: The code wraps options.sourceSqlQuery into baseSource
without removing trailing semicolons, which makes the resulting FROM (<query>)
invalid; before using options.sourceSqlQuery in baseSource (the expression
constructing baseSource), trim whitespace and strip any trailing semicolon
characters from options.sourceSqlQuery (e.g. remove one or more trailing ';' and
trailing whitespace) and then wrap the cleaned query in `(<cleanedQuery>) AS
"__sqlrooms_dashboard_map_source"`; keep the fallback to
quoteDeckMapSqlTableReference(options.tableReference) unchanged.

---

Nitpick comments:
In `@packages/mosaic/src/ai.ts`:
- Line 172: The prompt text hardcodes the tool name create_dashboard_map while
hosts can register tools under any key via extraTools; update the code to avoid
the implicit naming contract by introducing a single exported constant (e.g.,
MAP_TOOL_KEY) or a small registration helper (e.g., registerMapTool) and
reference that symbol in the prompt text instead of the literal string, and add
JSDoc on extraTools to document the expected key/registration helper so prompt
and tool key stay in sync (also apply the same change for the other occurrence
noted around line 197).
- Around line 485-491: Host-provided tools (hostTools from extraTools) are
currently spread after built-in entries in CreateDashboardAiToolsOptions (in the
function creating chartTools and hostTools), allowing silent overrides of
built-in tools like create_dashboard_artifact or any chart tool; change the
merge order or add collision detection: either spread hostTools before the
built-ins so built-ins win, or, inside the function that builds the final tool
map (where createChartTools, resolvedChartTypes, hostTools and chartTools are
combined), iterate hostTools keys and check for existing keys in
chartTools/built-ins and log/warn or throw if a collision is found (refer to
hostTools, createChartTools, createDashboardToolDeps, createDefaultChartTypes,
and the built-in key names such as create_dashboard_artifact) and choose the
desired behavior (prevent override by default or allow with explicit warning).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea38ca43-1b82-4842-8c58-59a642cd2ad3

📥 Commits

Reviewing files that changed from the base of the PR and between f3f0b9e and aa08b4e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • apps/sqlrooms-cli-ui/src/createDashboardToolDeps.ts
  • packages/deck/__tests__/dashboard-ai-map.test.ts
  • packages/deck/package.json
  • packages/deck/src/ai.ts
  • packages/deck/src/dashboard.tsx
  • packages/deck/src/index.ts
  • packages/deck/src/mapConfigUtils.ts
  • packages/mosaic/src/ai.ts

Comment thread packages/deck/src/mapConfigUtils.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/deck/src/ai.ts`:
- Around line 82-103: The sqlQuery path currently validates columns by calling
deps.resolveTable (so DeckMapDashboardToolParameters and downstream logic
validate against the base table schema), which breaks for queries that alias or
compute geo fields; change the validation so that when sqlQuery is provided you
either (A) accept an additional explicit queryColumns parameter (e.g., array of
column descriptors) in DeckMapDashboardToolParameters and validate/auto-detect
against that array instead of resolveTable, or (B) skip calling
deps.resolveTable and bypass table-column validation whenever the explicit map
columns (e.g., lon/lat/geometry) are supplied in the request; update the schema
and the code paths that call deps.resolveTable to branch on sqlQuery + presence
of explicit query columns and perform validation against the supplied columns
only.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7569c328-78d0-4812-aae0-29fff6831f89

📥 Commits

Reviewing files that changed from the base of the PR and between aa08b4e and b65542e.

📒 Files selected for processing (3)
  • packages/deck/__tests__/dashboard-ai-map.test.ts
  • packages/deck/src/ai.ts
  • packages/deck/src/index.ts

Comment thread packages/deck/src/ai.ts Outdated
(
context as
| (ChartToolExecutionContext & {getAiRunContext?: () => unknown})
| (ChartToolExecutionContext & {getAztiRunContext?: () => unknown})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo?

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/deck/__tests__/dashboard-ai-map.test.ts (1)

140-157: ⚡ Quick win

Consider strengthening the semicolon-stripping assertion.

The current assertion only checks the wrapped subquery still appears in the SQL but does not actually prove trailing semicolons were stripped — e.g. FROM (SELECT * FROM earthquakes; ;) AS "..." would also pass toContain(...). Asserting the absence of ; inside the parenthesized inner SQL (or matching the full normalized substring) would make the test meaningful for the stated behavior.

♻️ Proposed tightening
-    expect(
-      deps.panels[0].config.datasets.earthquakes.source.sqlQuery,
-    ).toContain(
-      'FROM (SELECT * FROM earthquakes) AS "__sqlrooms_dashboard_map_source"',
-    );
+    const wrappedSql: string =
+      deps.panels[0].config.datasets.earthquakes.source.sqlQuery;
+    expect(wrappedSql).toContain(
+      'FROM (SELECT * FROM earthquakes) AS "__sqlrooms_dashboard_map_source"',
+    );
+    expect(wrappedSql).not.toMatch(/;\s*\)\s*AS\s+"__sqlrooms_dashboard_map_source"/);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/deck/__tests__/dashboard-ai-map.test.ts` around lines 140 - 157, The
test 'strips trailing semicolons from wrapped source SQL queries' currently only
checks that the wrapped subquery string exists but not that trailing semicolons
were removed; update the assertion on
deps.panels[0].config.datasets.earthquakes.source.sqlQuery (after calling (tool
as any).execute with createDeckMapDashboardTool(createDeps())) to either (a)
assert the exact normalized wrapped substring equals FROM (SELECT * FROM
earthquakes) AS "__sqlrooms_dashboard_map_source" or (b) assert that there is no
';' character inside the parenthesized inner SQL (i.e., within the parentheses
following FROM), so the test proves trailing semicolons were stripped. Ensure
you reference the same fields used now:
deps.panels[0].config.datasets.earthquakes.source.sqlQuery and the execute call
on tool.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/deck/src/mapConfigUtils.ts`:
- Around line 126-131: The ternary that builds baseSource currently checks
options.sourceSqlQuery but injects cleanedSourceSqlQuery, which allows
whitespace/semicolon-only inputs to produce an empty subquery; change the
predicate to test cleanedSourceSqlQuery (truthiness) instead of
options.sourceSqlQuery so you only build `(${cleanedSourceSqlQuery}) AS
"__sqlrooms_dashboard_map_source"` when the cleaned string is non-empty, and
otherwise fall back to quoteDeckMapSqlTableReference(options.tableReference);
update the expression that defines baseSource accordingly.

---

Nitpick comments:
In `@packages/deck/__tests__/dashboard-ai-map.test.ts`:
- Around line 140-157: The test 'strips trailing semicolons from wrapped source
SQL queries' currently only checks that the wrapped subquery string exists but
not that trailing semicolons were removed; update the assertion on
deps.panels[0].config.datasets.earthquakes.source.sqlQuery (after calling (tool
as any).execute with createDeckMapDashboardTool(createDeps())) to either (a)
assert the exact normalized wrapped substring equals FROM (SELECT * FROM
earthquakes) AS "__sqlrooms_dashboard_map_source" or (b) assert that there is no
';' character inside the parenthesized inner SQL (i.e., within the parentheses
following FROM), so the test proves trailing semicolons were stripped. Ensure
you reference the same fields used now:
deps.panels[0].config.datasets.earthquakes.source.sqlQuery and the execute call
on tool.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20631480-e2a2-49a2-96f2-f168474004d1

📥 Commits

Reviewing files that changed from the base of the PR and between b65542e and 682a7d1.

📒 Files selected for processing (6)
  • packages/deck/__tests__/dashboard-ai-map.test.ts
  • packages/deck/src/ai.ts
  • packages/deck/src/mapConfigUtils.ts
  • packages/mosaic/README.md
  • packages/mosaic/__tests__/dashboard-ai.test.ts
  • packages/mosaic/src/ai.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/mosaic/README.md

Comment thread packages/deck/src/mapConfigUtils.ts
@ilyabo
ilyabo force-pushed the feat--Deck-map-ai-tool branch from 682a7d1 to 4dd6bea Compare May 21, 2026 14:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/deck/src/mapConfigUtils.ts (1)

126-131: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the cleaned SQL value to decide subquery wrapping.

Line 129 checks the raw options.sourceSqlQuery, but Line 130 injects cleanedSourceSqlQuery. Inputs like " ; " become empty after cleaning and produce invalid SQL (FROM () AS ...).

Proposed fix
   const cleanedSourceSqlQuery = options.sourceSqlQuery
     ?.trim()
     .replace(/(?:\s*;+\s*)+$/, '');
-  const baseSource = options.sourceSqlQuery
+  const baseSource = cleanedSourceSqlQuery
     ? `(${cleanedSourceSqlQuery}) AS "__sqlrooms_dashboard_map_source"`
     : quoteDeckMapSqlTableReference(options.tableReference);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/deck/src/mapConfigUtils.ts` around lines 126 - 131, The code uses
options.sourceSqlQuery to decide whether to wrap a subquery but inserts
cleanedSourceSqlQuery into the final SQL, which can be empty (e.g., " ; ") and
produce invalid SQL; change the decision to use the cleaned value: compute
cleanedSourceSqlQuery first, then set baseSource to `(${cleanedSourceSqlQuery})
AS "__sqlrooms_dashboard_map_source"` only when cleanedSourceSqlQuery is
non-empty (truthy), otherwise fall back to
quoteDeckMapSqlTableReference(options.tableReference); reference
cleanedSourceSqlQuery, options.sourceSqlQuery, baseSource, and
quoteDeckMapSqlTableReference when making this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/deck/src/mapConfigUtils.ts`:
- Around line 126-131: The code uses options.sourceSqlQuery to decide whether to
wrap a subquery but inserts cleanedSourceSqlQuery into the final SQL, which can
be empty (e.g., " ; ") and produce invalid SQL; change the decision to use the
cleaned value: compute cleanedSourceSqlQuery first, then set baseSource to
`(${cleanedSourceSqlQuery}) AS "__sqlrooms_dashboard_map_source"` only when
cleanedSourceSqlQuery is non-empty (truthy), otherwise fall back to
quoteDeckMapSqlTableReference(options.tableReference); reference
cleanedSourceSqlQuery, options.sourceSqlQuery, baseSource, and
quoteDeckMapSqlTableReference when making this change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f6e9844e-b967-4673-bf5a-7b28977c97ff

📥 Commits

Reviewing files that changed from the base of the PR and between 682a7d1 and 4dd6bea.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • packages/deck/__tests__/createDeckJsonConfiguration.test.ts
  • packages/deck/__tests__/dashboard-ai-map.test.ts
  • packages/deck/__tests__/mapLayerConfigUtils.test.ts
  • packages/deck/package.json
  • packages/deck/src/MapSettings.tsx
  • packages/deck/src/ai.ts
  • packages/deck/src/dashboard.tsx
  • packages/deck/src/index.ts
  • packages/deck/src/json/colorScaleFunction.ts
  • packages/deck/src/mapConfigUtils.ts
  • packages/deck/src/mapLayerConfigUtils.ts
  • packages/mosaic/README.md
  • packages/mosaic/__tests__/dashboard-ai.test.ts
  • packages/mosaic/src/ai.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/mosaic/README.md
  • packages/deck/package.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/deck/src/mapConfigUtils.ts (2)

221-260: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Allow SQL-projected geometry aliases here.

When sourceSqlQuery projects a new geometry alias and the caller passes it via geometryColumn, this unconditional ensureDeckMapColumnExists(...) check rejects a valid config because options.columns only describes the base table. That breaks SQL-backed geometry panels before they can be created.

Suggested fix
   if (detectedGeometryColumn) {
-    ensureDeckMapColumnExists(
-      options.columns,
-      detectedGeometryColumn.geometryColumn,
-      'geometry',
-    );
+    const shouldValidateAgainstTableColumns =
+      !options.sourceSqlQuery || !explicitGeometryColumn;
+    if (shouldValidateAgainstTableColumns) {
+      ensureDeckMapColumnExists(
+        options.columns,
+        detectedGeometryColumn.geometryColumn,
+        'geometry',
+      );
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/deck/src/mapConfigUtils.ts` around lines 221 - 260, The code
unconditionally calls ensureDeckMapColumnExists when a detectedGeometryColumn is
present, which wrongly rejects cases where the geometry alias comes from a
projected sourceSqlQuery; update the guard so that ensureDeckMapColumnExists is
only invoked for base-table column checks (i.e., when options.sourceSqlQuery is
not provided). In practice, modify the block around detectedGeometryColumn and
ensureDeckMapColumnExists so it skips the existence check if
options.sourceSqlQuery is set (allowing SQL-projected geometry aliases passed
via geometryColumn to succeed).

330-345: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't overwrite existing SQL-backed geometry panels during regeneration.

This new geometry fallback now rebuilds configs for geometry-only tables too, but the rebuild only uses table.table/detected columns. If the existing panel was backed by source.sqlQuery or an explicit geometry column/hint, regeneration replaces it with a raw-table dataset and can break an otherwise working map. Please carry the existing dataset source/geometry settings forward here, or bail out when the current panel is SQL-backed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/deck/src/mapConfigUtils.ts` around lines 330 - 345, The regeneration
currently always calls createDeckMapDashboardConfigForTable and overwrites
panel.config even for SQL-backed or explicitly-hinted geometry panels; change
this to first inspect the existingConfig (panel.config) and if
existingConfig.source?.sqlQuery exists or an explicit geometry column/hint is
present, preserve the current config by returning existingConfig (i.e., bail
out) instead of rebuilding, or alternatively merge the existing source/geometry
settings into the payload passed to createDeckMapDashboardConfigForTable so
source/sqlQuery and explicit geometryColumn/latitude/longitude hints are carried
forward; check for source.sqlQuery and any explicit geometry hints before
calling createDeckMapDashboardConfigForTable and act accordingly.
🧹 Nitpick comments (2)
packages/mosaic/src/chart-runtime.ts (1)

118-129: ⚡ Quick win

Make disabled override semantics explicit.

At Line 118, only truthy override.disabled is handled, so disabled: false currently behaves like “not provided” and inherits the base value. If this is intended as a true override object, it should either apply explicit false or narrow the type to a one-way flag (disabled?: true).

Suggested adjustment (support explicit false override)
-  if (override.disabled) {
-    return {
-      ...(basePolicy ?? {}),
-      disabled: true,
-    };
-  }
-
   return {
     ...(basePolicy ?? {}),
+    ...(override.disabled !== undefined ? {disabled: override.disabled} : {}),
     ...(override.maxRows !== undefined ? {maxRows: override.maxRows} : {}),
     ...(override.reason !== undefined ? {reason: override.reason} : {}),
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mosaic/src/chart-runtime.ts` around lines 118 - 129, The current
merge logic in chart-runtime.ts treats override.disabled truthily, so a consumer
cannot explicitly set disabled: false; update the merge in the function that
constructs the final policy (the block currently returning ...(basePolicy ??
{}), ...(override.maxRows...), etc.) to treat disabled as an explicit override
by checking override.disabled !== undefined and, when present, setting disabled:
override.disabled; alternatively (if you prefer one-way flag semantics) change
the override type to only allow disabled?: true and keep the existing truthy
check—apply the first option to preserve explicit false semantics on the
returned policy.
packages/deck/src/ai.ts (1)

101-129: 💤 Low value

Duplicate reasoning field in schema extension.

DeckMapDashboardToolParameters extends DeckMapConfigToolParameters which already defines a reasoning field (lines 92-94). The extension redefines reasoning again at lines 126-128, which shadows the inherited field. While Zod will use the extended definition, this redundancy is confusing and may cause maintenance issues.

♻️ Remove the duplicate reasoning field
 export const DeckMapDashboardToolParameters =
   DeckMapConfigToolParameters.extend({
     artifactId: z
       .string()
       .optional()
       .describe(
         'Optional dashboard artifact ID. Defaults to current dashboard.',
       ),
     tableName: z
       .string()
       .optional()
       .describe(
         'Optional table name used only to select/resolve the target dashboard table. Data sources still come from config.datasets.',
       ),
     createArtifactIfMissing: z
       .boolean()
       .optional()
       .default(true)
       .describe('If true, create dashboard artifact if missing.'),
     panelId: z
       .string()
       .optional()
       .describe(
         'Optional panel ID. If provided, updates the existing map panel instead of creating a new one.',
       ),
-    reasoning: z
-      .string()
-      .describe('Brief rationale for creating the map panel.'),
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/deck/src/ai.ts` around lines 101 - 129,
DeckMapDashboardToolParameters currently redefines the reasoning field that is
already declared on DeckMapConfigToolParameters; remove the duplicate reasoning
entry from the DeckMapDashboardToolParameters schema so the inherited reasoning
from DeckMapConfigToolParameters is used (leave other fields like artifactId,
tableName, createArtifactIfMissing, and panelId intact and unchanged).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/deck/src/mapConfigUtils.ts`:
- Around line 221-260: The code unconditionally calls ensureDeckMapColumnExists
when a detectedGeometryColumn is present, which wrongly rejects cases where the
geometry alias comes from a projected sourceSqlQuery; update the guard so that
ensureDeckMapColumnExists is only invoked for base-table column checks (i.e.,
when options.sourceSqlQuery is not provided). In practice, modify the block
around detectedGeometryColumn and ensureDeckMapColumnExists so it skips the
existence check if options.sourceSqlQuery is set (allowing SQL-projected
geometry aliases passed via geometryColumn to succeed).
- Around line 330-345: The regeneration currently always calls
createDeckMapDashboardConfigForTable and overwrites panel.config even for
SQL-backed or explicitly-hinted geometry panels; change this to first inspect
the existingConfig (panel.config) and if existingConfig.source?.sqlQuery exists
or an explicit geometry column/hint is present, preserve the current config by
returning existingConfig (i.e., bail out) instead of rebuilding, or
alternatively merge the existing source/geometry settings into the payload
passed to createDeckMapDashboardConfigForTable so source/sqlQuery and explicit
geometryColumn/latitude/longitude hints are carried forward; check for
source.sqlQuery and any explicit geometry hints before calling
createDeckMapDashboardConfigForTable and act accordingly.

---

Nitpick comments:
In `@packages/deck/src/ai.ts`:
- Around line 101-129: DeckMapDashboardToolParameters currently redefines the
reasoning field that is already declared on DeckMapConfigToolParameters; remove
the duplicate reasoning entry from the DeckMapDashboardToolParameters schema so
the inherited reasoning from DeckMapConfigToolParameters is used (leave other
fields like artifactId, tableName, createArtifactIfMissing, and panelId intact
and unchanged).

In `@packages/mosaic/src/chart-runtime.ts`:
- Around line 118-129: The current merge logic in chart-runtime.ts treats
override.disabled truthily, so a consumer cannot explicitly set disabled: false;
update the merge in the function that constructs the final policy (the block
currently returning ...(basePolicy ?? {}), ...(override.maxRows...), etc.) to
treat disabled as an explicit override by checking override.disabled !==
undefined and, when present, setting disabled: override.disabled; alternatively
(if you prefer one-way flag semantics) change the override type to only allow
disabled?: true and keep the existing truthy check—apply the first option to
preserve explicit false semantics on the returned policy.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83b78f6c-d73b-49f3-a9bf-bcdfdee12c8d

📥 Commits

Reviewing files that changed from the base of the PR and between 4dd6bea and e1cc53c.

📒 Files selected for processing (27)
  • apps/sqlrooms-cli-ui/src/createDashboardAgent.ts
  • apps/sqlrooms-cli-ui/src/createDashboardAiTools.ts
  • apps/sqlrooms-cli-ui/src/createDashboardToolDeps.ts
  • apps/sqlrooms-cli-ui/src/store.ts
  • packages/deck/__tests__/dashboard-ai-map.test.ts
  • packages/deck/__tests__/mapLayerConfigUtils.test.ts
  • packages/deck/src/MapSettings.tsx
  • packages/deck/src/ai.ts
  • packages/deck/src/dashboard.tsx
  • packages/deck/src/dashboardConfig.ts
  • packages/deck/src/mapConfigUtils.ts
  • packages/deck/src/mapLayerConfigUtils.ts
  • packages/mosaic/__tests__/dashboard-ai.test.ts
  • packages/mosaic/src/ai.ts
  • packages/mosaic/src/chart-runtime.ts
  • packages/mosaic/src/chart-types/box-plot/schema.ts
  • packages/mosaic/src/chart-types/bubble-chart/schema.ts
  • packages/mosaic/src/chart-types/chart-config.ts
  • packages/mosaic/src/chart-types/count-plot/schema.ts
  • packages/mosaic/src/chart-types/custom-spec/schema.ts
  • packages/mosaic/src/chart-types/data-policy-schema.ts
  • packages/mosaic/src/chart-types/heatmap/schema.ts
  • packages/mosaic/src/chart-types/histogram/schema.ts
  • packages/mosaic/src/chart-types/index.ts
  • packages/mosaic/src/chart-types/line-chart/schema.ts
  • packages/mosaic/src/chart/MosaicDashboardChartContent.tsx
  • packages/mosaic/src/index.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/mosaic/src/chart-types/index.ts
  • packages/mosaic/src/chart-types/data-policy-schema.ts

@ilyabo
ilyabo merged commit 3f47820 into main May 22, 2026
3 checks passed
@ilyabo
ilyabo deleted the feat--Deck-map-ai-tool branch May 22, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants