Skip to content

Commit 820396a

Browse files
committed
Document SQL visualization chart contract
1 parent 1b756f0 commit 820396a

3 files changed

Lines changed: 147 additions & 1 deletion

File tree

Architecture/sql-result-visualization.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,89 @@ This architecture governs:
6565
- The supported chart types MUST be constrained to the known allowlist above.
6666
- The implementation MUST retry up to two times when the model returns malformed JSON or an invalid chart config, and each correction prompt MUST include the latest validation error.
6767

68+
## Chart Config Examples
69+
70+
Vertical or horizontal bar charts use one category key and one or more numeric series keys:
71+
72+
```json
73+
{
74+
"config": {
75+
"type": "bar",
76+
"title": "Incidents by severity",
77+
"xKey": "severity",
78+
"series": [{ "key": "count", "label": "Incidents" }],
79+
"data": [
80+
{ "severity": "Low", "count": 12 },
81+
{ "severity": "High", "count": 3 }
82+
]
83+
}
84+
}
85+
```
86+
87+
Stacked bar charts use separate numeric fields for each stack segment, not one long/tidy row per segment:
88+
89+
```json
90+
{
91+
"config": {
92+
"type": "horizontal-bar",
93+
"title": "Team skills by organization",
94+
"xKey": "organization",
95+
"stacked": true,
96+
"series": [
97+
{ "key": "typescript", "label": "TypeScript" },
98+
{ "key": "postgres", "label": "Postgres" }
99+
],
100+
"data": [
101+
{ "organization": "Acme", "typescript": 4, "postgres": 2 },
102+
{ "organization": "Globex", "typescript": 1, "postgres": 5 }
103+
]
104+
}
105+
}
106+
```
107+
108+
Line charts require date-like x-values:
109+
110+
```json
111+
{
112+
"config": {
113+
"type": "line",
114+
"title": "Rows created over time",
115+
"xKey": "day",
116+
"series": [{ "key": "created", "label": "Created rows" }],
117+
"data": [
118+
{ "day": "2026-06-01", "created": 18 },
119+
{ "day": "2026-06-02", "created": 27 }
120+
]
121+
}
122+
}
123+
```
124+
125+
Pie-like charts use one label key and one numeric value key:
126+
127+
```json
128+
{
129+
"config": {
130+
"type": "doughnut",
131+
"title": "Feature flag states",
132+
"labelKey": "state",
133+
"valueKey": "count",
134+
"data": [
135+
{ "state": "Enabled", "count": 9 },
136+
{ "state": "Disabled", "count": 4 }
137+
]
138+
}
139+
}
140+
```
141+
142+
## Renderer Contract
143+
144+
- `bar` and `horizontal-bar` render through `BarChart`, `Bar`, `BarXAxis`, and `BarYAxis`.
145+
- `line` renders through `LineChart`, `Line`, and `XAxis`.
146+
- `pie` and `doughnut` render through `PieChart` and `PieSlice`.
147+
- All chart types use the shared Bklit `Grid` and `ChartTooltip` primitives where applicable.
148+
- Series colors default to Studio chart CSS variables (`--chart-1` through `--chart-5`) unless a validated series color is provided.
149+
- The renderer MUST ignore arbitrary chart-library options. All display behavior is derived from the validated Studio config and local component composition.
150+
68151
## Chart Lifecycle Contract
69152

70153
- Chart rendering MUST use the Bklit ShadCN chart primitives checked into `ui/components/charts`.

FEATURES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ If AI-generated SQL fails when the user runs it, Studio sends the original reque
228228

229229
When SQL query results are visible and `llm` is configured, Studio can also turn the returned rows into an in-grid Bklit visualization.
230230
The visualization uses a minimal summary-row trigger labeled `Visualize data with AI`, right-aligned beside the query result count, and mounts the generated chart above the SQL result headers inside the shared scrollable grid without a regenerate control.
231-
Studio sends the executed SQL, the concrete database engine, and the full result row set to the model, and when the result came from `Generate SQL with AI` it also includes the original natural-language request for extra visualization context. The model is asked for a strict Bklit chart config for bar, horizontal bar, line, pie, doughnut, or stacked bar charts, and Studio validates that schema before rendering.
231+
Studio sends the executed SQL, the concrete database engine, and the full result row set to the model, and when the result came from `Generate SQL with AI` it also includes the original natural-language request for extra visualization context. The model is asked for a strict Studio-owned Bklit chart config for `bar`, `horizontal-bar`, `line`, `pie`, `doughnut`, or stacked `bar`/`horizontal-bar` charts; arbitrary Chart.js-style options, callbacks, plugins, and non-primitive row values are rejected before rendering.
232232
Mounted charts sit inside an in-grid background band that stays tied to the visible result viewport instead of the total table width, while the chart itself stays centered and width-clamped between 300px and 1200px so wide result grids do not force giant charts.
233233
When SQL is generated through AI, the same model call also decides whether the expected result is graph-worthy; if it says yes, Studio auto-generates the chart after the user manually runs that generated SQL instead of waiting for a separate chart button click.
234234
If another query starts running, the visualization resets immediately so stale charts do not persist across changing result sets. Visualization generation also retries up to two times on malformed JSON, invalid chart configs, or explicit provider output-limit failures.

README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,69 @@ type StudioLlmResponse =
138138

139139
Studio treats `output-limit-exceeded` as a first-class retry signal for SQL generation and visualization correction loops. When `sqlLint` is available, Studio validates AI-generated SQL before showing it and feeds lint diagnostics back through the same `sql-generation` transport when correction is needed. If AI-generated SQL still fails after the user manually runs it, Studio sends the failed SQL and database error back through that same transport so the model can propose corrected SQL without auto-running it. All prompting and retry behavior live in Studio itself, so host implementations should stay transport-only.
140140

141+
### SQL Result Visualization Charts
142+
143+
SQL result visualization uses the shared `llm` hook with `task: "sql-visualization"`. The host does not need to provide chart components, Chart.js options, callbacks, plugins, or chart-specific APIs. Studio builds the prompt from the executed SQL, database engine, full result rows, and the original AI SQL request when available; the host only forwards that prompt to the model and returns the model text.
144+
145+
Studio validates the model response as a small Bklit chart config before rendering. The response must be strict JSON in this shape:
146+
147+
```ts
148+
type SqlResultVisualizationResponse = {
149+
config:
150+
| {
151+
type: "bar" | "horizontal-bar" | "line";
152+
title?: string;
153+
xKey: string;
154+
series: Array<{
155+
key: string;
156+
label?: string;
157+
color?: string;
158+
}>;
159+
stacked?: boolean;
160+
data: Array<Record<string, string | number | boolean | null>>;
161+
}
162+
| {
163+
type: "pie" | "doughnut";
164+
title?: string;
165+
labelKey: string;
166+
valueKey: string;
167+
data: Array<Record<string, string | number | boolean | null>>;
168+
};
169+
};
170+
```
171+
172+
Chart rules:
173+
174+
- `bar` and `horizontal-bar` require `xKey` plus one or more numeric `series` fields.
175+
- `stacked: true` is supported only for `bar` and `horizontal-bar`.
176+
- `horizontal-bar` is preferred for ranked categorical data and long category labels.
177+
- `line` requires date-like `xKey` values: ISO dates, ISO datetimes, or epoch milliseconds.
178+
- `pie` and `doughnut` require `labelKey` and a numeric `valueKey`.
179+
- `data` rows must contain plain JSON primitive values only.
180+
181+
Example stacked horizontal bar response:
182+
183+
```json
184+
{
185+
"config": {
186+
"type": "horizontal-bar",
187+
"title": "Team skills by organization",
188+
"xKey": "organization",
189+
"stacked": true,
190+
"series": [
191+
{ "key": "typescript", "label": "TypeScript" },
192+
{ "key": "postgres", "label": "Postgres" }
193+
],
194+
"data": [
195+
{ "organization": "Acme", "typescript": 4, "postgres": 2 },
196+
{ "organization": "Globex", "typescript": 1, "postgres": 5 }
197+
]
198+
}
199+
}
200+
```
201+
202+
Invalid JSON, unsupported chart types, non-primitive row values, missing keys, non-numeric series values, and non-date line x-values are rejected and fed back to the model for correction. The normative implementation details live in [`Architecture/sql-result-visualization.md`](Architecture/sql-result-visualization.md).
203+
141204
## Integration Checklist
142205

143206
Studio is an embeddable React surface, not a standalone app shell. A production integration should:

0 commit comments

Comments
 (0)