Skip to content

Commit ff1db57

Browse files
authored
Merge pull request #965 from nteract/chatwithchart
Add AI interrogation and chart-suggestion features
2 parents c9561da + f5c3b07 commit ff1db57

129 files changed

Lines changed: 14124 additions & 121 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.clinerules

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,64 @@ Canvas scene builders read CSS variables via `getComputedStyle` on the canvas DO
267267
## AI Features
268268
`onObservation`/`useChartObserver`, `toConfig`/`fromConfig`/`toURL`/`fromURL`/`copyConfig`/`configToJSX`, `validateProps(component, props)`, `diagnoseConfig(component, props)`, `exportChart(div, { format })`, `npx semiotic-ai --doctor`
269269

270+
### Conversational Interrogation (`semiotic/ai`)
271+
Headless hook for "chat with the chart" interactions. The library ships no UI — bring your own chat surface.
272+
- **`useChartInterrogation({ data, onQuery, componentName?, props?, initialAnnotations? })`** → `{ ask(query), history, summary, annotations, loading, error, reset }`
273+
- **`onQuery: (query, context) => Promise<{ answer, annotations? }>`** — call your LLM here. `context` is `{ data, summary, componentName?, props? }`.
274+
- **`summary`**: LLM-friendly statistical summary (`rowCount`, per-field `{ min, max, mean, median }` for numerics, top-k for categoricals, ISO range for dates). Available before any ask().
275+
- **`annotations`**: Merged `initialAnnotations` + latest AI response. Wire to the chart's `annotations` prop for visual highlighting.
276+
- **`summarizeData(data, options?)`**: Standalone for server-side prompting or batch jobs.
277+
- **MCP Tool**: `interrogateChart(component, props, query)` returns the same statistical summary and AI-facing instructions.
278+
279+
```jsx
280+
import { LineChart, useChartInterrogation } from "semiotic/ai"
281+
282+
function InterrogatableChart({ data }) {
283+
const { ask, history, annotations, loading } = useChartInterrogation({
284+
data,
285+
componentName: "LineChart",
286+
props: { xAccessor: "month", yAccessor: "revenue" },
287+
onQuery: async (query, { summary }) => {
288+
const res = await myLLMCall(query, summary)
289+
return { answer: res.text, annotations: res.highlights }
290+
},
291+
})
292+
return (
293+
<>
294+
<LineChart data={data} xAccessor="month" yAccessor="revenue" annotations={annotations} />
295+
<YourChatUI history={history} loading={loading} onAsk={ask} />
296+
</>
297+
)
298+
}
299+
```
300+
301+
### Chart Capability Layer (`semiotic/ai`)
302+
Heuristic chart-suggestion engine. Charts ship capability descriptors next to their TSX files; the engine ranks them against a profiled dataset by intent. No LLM call required.
303+
304+
- **`profileData(data, { rawInput?, seriesField? })`** → `ChartDataProfile` (extends `DataSummary`): candidate fields per role (x/y/series/category/size/time), distinct counts, monotonicity, structure detection (hierarchy/network/geo).
305+
- **`suggestCharts(data, { intent?, allow?, deny?, maxResults?, includeVariants?, minScore? })`** → ranked `Suggestion[]` with `{ component, family, importPath, variant?, score, intentScores, rubric, reasons, caveats, props }`. `props` is spreadable directly into the matching chart.
306+
- **`scoreChart(component, data, { intent?, variantKey? })`** → evaluate a specific chart for a dataset (does it fit, how well, why/why not).
307+
- **`useChartSuggestions(data, options)`** → memoized React hook returning `{ suggestions, profile }`.
308+
- **`registerChartCapability(capability)`** / **`unregisterChartCapability(name)`** — runtime registration for custom charts.
309+
- **Intent taxonomy**: 13 built-in intents (`trend`, `compare-series`, `compare-categories`, `rank`, `part-to-whole`, `distribution`, `correlation`, `flow`, `hierarchy`, `geo`, `outlier-detection`, `composition-over-time`, `change-detection`). Extend via `registerIntent(descriptor)`.
310+
- **Capability authoring**: create `Foo.capability.ts` next to `Foo.tsx`, then append to the registry in `src/components/ai/chartCapabilities.ts`. Each capability declares `family`, `rubric` (familiarity/accuracy/precision 1-5), `fits(profile)` gate, `intentScores`, optional `variants` with `intentDeltas`, and `buildProps(profile, variant)`.
311+
- **Variants encode that settings change what a chart is good for**: e.g. `StackedAreaChart`'s `streamgraph` variant boosts trend but penalizes part-to-whole.
312+
- **Interrogation tie-in**: pass `includeSuggestions: true` to `useChartInterrogation` and the same ranked list lands in `context.suggestions` for the LLM.
313+
- **MCP tool**: `suggestCharts(data, intent?)` returns the ranked list as structured content.
314+
315+
```jsx
316+
import { useChartSuggestions, LineChart, BarChart, /* ... */ } from "semiotic/ai"
317+
318+
const COMPONENT_MAP = { LineChart, BarChart, /* ... */ }
319+
function SuggestedChart({ data, intent }) {
320+
const { suggestions } = useChartSuggestions(data, { intent })
321+
const top = suggestions[0]
322+
if (!top) return null
323+
const Component = COMPONENT_MAP[top.component]
324+
return <Component {...top.props} />
325+
}
326+
```
327+
270328

271329
## AI Behavior Contracts
272330

.cursorrules

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,64 @@ Canvas scene builders read CSS variables via `getComputedStyle` on the canvas DO
267267
## AI Features
268268
`onObservation`/`useChartObserver`, `toConfig`/`fromConfig`/`toURL`/`fromURL`/`copyConfig`/`configToJSX`, `validateProps(component, props)`, `diagnoseConfig(component, props)`, `exportChart(div, { format })`, `npx semiotic-ai --doctor`
269269

270+
### Conversational Interrogation (`semiotic/ai`)
271+
Headless hook for "chat with the chart" interactions. The library ships no UI — bring your own chat surface.
272+
- **`useChartInterrogation({ data, onQuery, componentName?, props?, initialAnnotations? })`** → `{ ask(query), history, summary, annotations, loading, error, reset }`
273+
- **`onQuery: (query, context) => Promise<{ answer, annotations? }>`** — call your LLM here. `context` is `{ data, summary, componentName?, props? }`.
274+
- **`summary`**: LLM-friendly statistical summary (`rowCount`, per-field `{ min, max, mean, median }` for numerics, top-k for categoricals, ISO range for dates). Available before any ask().
275+
- **`annotations`**: Merged `initialAnnotations` + latest AI response. Wire to the chart's `annotations` prop for visual highlighting.
276+
- **`summarizeData(data, options?)`**: Standalone for server-side prompting or batch jobs.
277+
- **MCP Tool**: `interrogateChart(component, props, query)` returns the same statistical summary and AI-facing instructions.
278+
279+
```jsx
280+
import { LineChart, useChartInterrogation } from "semiotic/ai"
281+
282+
function InterrogatableChart({ data }) {
283+
const { ask, history, annotations, loading } = useChartInterrogation({
284+
data,
285+
componentName: "LineChart",
286+
props: { xAccessor: "month", yAccessor: "revenue" },
287+
onQuery: async (query, { summary }) => {
288+
const res = await myLLMCall(query, summary)
289+
return { answer: res.text, annotations: res.highlights }
290+
},
291+
})
292+
return (
293+
<>
294+
<LineChart data={data} xAccessor="month" yAccessor="revenue" annotations={annotations} />
295+
<YourChatUI history={history} loading={loading} onAsk={ask} />
296+
</>
297+
)
298+
}
299+
```
300+
301+
### Chart Capability Layer (`semiotic/ai`)
302+
Heuristic chart-suggestion engine. Charts ship capability descriptors next to their TSX files; the engine ranks them against a profiled dataset by intent. No LLM call required.
303+
304+
- **`profileData(data, { rawInput?, seriesField? })`** → `ChartDataProfile` (extends `DataSummary`): candidate fields per role (x/y/series/category/size/time), distinct counts, monotonicity, structure detection (hierarchy/network/geo).
305+
- **`suggestCharts(data, { intent?, allow?, deny?, maxResults?, includeVariants?, minScore? })`** → ranked `Suggestion[]` with `{ component, family, importPath, variant?, score, intentScores, rubric, reasons, caveats, props }`. `props` is spreadable directly into the matching chart.
306+
- **`scoreChart(component, data, { intent?, variantKey? })`** → evaluate a specific chart for a dataset (does it fit, how well, why/why not).
307+
- **`useChartSuggestions(data, options)`** → memoized React hook returning `{ suggestions, profile }`.
308+
- **`registerChartCapability(capability)`** / **`unregisterChartCapability(name)`** — runtime registration for custom charts.
309+
- **Intent taxonomy**: 13 built-in intents (`trend`, `compare-series`, `compare-categories`, `rank`, `part-to-whole`, `distribution`, `correlation`, `flow`, `hierarchy`, `geo`, `outlier-detection`, `composition-over-time`, `change-detection`). Extend via `registerIntent(descriptor)`.
310+
- **Capability authoring**: create `Foo.capability.ts` next to `Foo.tsx`, then append to the registry in `src/components/ai/chartCapabilities.ts`. Each capability declares `family`, `rubric` (familiarity/accuracy/precision 1-5), `fits(profile)` gate, `intentScores`, optional `variants` with `intentDeltas`, and `buildProps(profile, variant)`.
311+
- **Variants encode that settings change what a chart is good for**: e.g. `StackedAreaChart`'s `streamgraph` variant boosts trend but penalizes part-to-whole.
312+
- **Interrogation tie-in**: pass `includeSuggestions: true` to `useChartInterrogation` and the same ranked list lands in `context.suggestions` for the LLM.
313+
- **MCP tool**: `suggestCharts(data, intent?)` returns the ranked list as structured content.
314+
315+
```jsx
316+
import { useChartSuggestions, LineChart, BarChart, /* ... */ } from "semiotic/ai"
317+
318+
const COMPONENT_MAP = { LineChart, BarChart, /* ... */ }
319+
function SuggestedChart({ data, intent }) {
320+
const { suggestions } = useChartSuggestions(data, { intent })
321+
const top = suggestions[0]
322+
if (!top) return null
323+
const Component = COMPONENT_MAP[top.component]
324+
return <Component {...top.props} />
325+
}
326+
```
327+
270328

271329
## AI Behavior Contracts
272330

.github/copilot-instructions.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,64 @@ Canvas scene builders read CSS variables via `getComputedStyle` on the canvas DO
267267
## AI Features
268268
`onObservation`/`useChartObserver`, `toConfig`/`fromConfig`/`toURL`/`fromURL`/`copyConfig`/`configToJSX`, `validateProps(component, props)`, `diagnoseConfig(component, props)`, `exportChart(div, { format })`, `npx semiotic-ai --doctor`
269269

270+
### Conversational Interrogation (`semiotic/ai`)
271+
Headless hook for "chat with the chart" interactions. The library ships no UI — bring your own chat surface.
272+
- **`useChartInterrogation({ data, onQuery, componentName?, props?, initialAnnotations? })`**`{ ask(query), history, summary, annotations, loading, error, reset }`
273+
- **`onQuery: (query, context) => Promise<{ answer, annotations? }>`** — call your LLM here. `context` is `{ data, summary, componentName?, props? }`.
274+
- **`summary`**: LLM-friendly statistical summary (`rowCount`, per-field `{ min, max, mean, median }` for numerics, top-k for categoricals, ISO range for dates). Available before any ask().
275+
- **`annotations`**: Merged `initialAnnotations` + latest AI response. Wire to the chart's `annotations` prop for visual highlighting.
276+
- **`summarizeData(data, options?)`**: Standalone for server-side prompting or batch jobs.
277+
- **MCP Tool**: `interrogateChart(component, props, query)` returns the same statistical summary and AI-facing instructions.
278+
279+
```jsx
280+
import { LineChart, useChartInterrogation } from "semiotic/ai"
281+
282+
function InterrogatableChart({ data }) {
283+
const { ask, history, annotations, loading } = useChartInterrogation({
284+
data,
285+
componentName: "LineChart",
286+
props: { xAccessor: "month", yAccessor: "revenue" },
287+
onQuery: async (query, { summary }) => {
288+
const res = await myLLMCall(query, summary)
289+
return { answer: res.text, annotations: res.highlights }
290+
},
291+
})
292+
return (
293+
<>
294+
<LineChart data={data} xAccessor="month" yAccessor="revenue" annotations={annotations} />
295+
<YourChatUI history={history} loading={loading} onAsk={ask} />
296+
</>
297+
)
298+
}
299+
```
300+
301+
### Chart Capability Layer (`semiotic/ai`)
302+
Heuristic chart-suggestion engine. Charts ship capability descriptors next to their TSX files; the engine ranks them against a profiled dataset by intent. No LLM call required.
303+
304+
- **`profileData(data, { rawInput?, seriesField? })`**`ChartDataProfile` (extends `DataSummary`): candidate fields per role (x/y/series/category/size/time), distinct counts, monotonicity, structure detection (hierarchy/network/geo).
305+
- **`suggestCharts(data, { intent?, allow?, deny?, maxResults?, includeVariants?, minScore? })`** → ranked `Suggestion[]` with `{ component, family, importPath, variant?, score, intentScores, rubric, reasons, caveats, props }`. `props` is spreadable directly into the matching chart.
306+
- **`scoreChart(component, data, { intent?, variantKey? })`** → evaluate a specific chart for a dataset (does it fit, how well, why/why not).
307+
- **`useChartSuggestions(data, options)`** → memoized React hook returning `{ suggestions, profile }`.
308+
- **`registerChartCapability(capability)`** / **`unregisterChartCapability(name)`** — runtime registration for custom charts.
309+
- **Intent taxonomy**: 13 built-in intents (`trend`, `compare-series`, `compare-categories`, `rank`, `part-to-whole`, `distribution`, `correlation`, `flow`, `hierarchy`, `geo`, `outlier-detection`, `composition-over-time`, `change-detection`). Extend via `registerIntent(descriptor)`.
310+
- **Capability authoring**: create `Foo.capability.ts` next to `Foo.tsx`, then append to the registry in `src/components/ai/chartCapabilities.ts`. Each capability declares `family`, `rubric` (familiarity/accuracy/precision 1-5), `fits(profile)` gate, `intentScores`, optional `variants` with `intentDeltas`, and `buildProps(profile, variant)`.
311+
- **Variants encode that settings change what a chart is good for**: e.g. `StackedAreaChart`'s `streamgraph` variant boosts trend but penalizes part-to-whole.
312+
- **Interrogation tie-in**: pass `includeSuggestions: true` to `useChartInterrogation` and the same ranked list lands in `context.suggestions` for the LLM.
313+
- **MCP tool**: `suggestCharts(data, intent?)` returns the ranked list as structured content.
314+
315+
```jsx
316+
import { useChartSuggestions, LineChart, BarChart, /* ... */ } from "semiotic/ai"
317+
318+
const COMPONENT_MAP = { LineChart, BarChart, /* ... */ }
319+
function SuggestedChart({ data, intent }) {
320+
const { suggestions } = useChartSuggestions(data, { intent })
321+
const top = suggestions[0]
322+
if (!top) return null
323+
const Component = COMPONENT_MAP[top.component]
324+
return <Component {...top.props} />
325+
}
326+
```
327+
270328

271329
## AI Behavior Contracts
272330

.windsurfrules

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,64 @@ Canvas scene builders read CSS variables via `getComputedStyle` on the canvas DO
267267
## AI Features
268268
`onObservation`/`useChartObserver`, `toConfig`/`fromConfig`/`toURL`/`fromURL`/`copyConfig`/`configToJSX`, `validateProps(component, props)`, `diagnoseConfig(component, props)`, `exportChart(div, { format })`, `npx semiotic-ai --doctor`
269269

270+
### Conversational Interrogation (`semiotic/ai`)
271+
Headless hook for "chat with the chart" interactions. The library ships no UI — bring your own chat surface.
272+
- **`useChartInterrogation({ data, onQuery, componentName?, props?, initialAnnotations? })`** → `{ ask(query), history, summary, annotations, loading, error, reset }`
273+
- **`onQuery: (query, context) => Promise<{ answer, annotations? }>`** — call your LLM here. `context` is `{ data, summary, componentName?, props? }`.
274+
- **`summary`**: LLM-friendly statistical summary (`rowCount`, per-field `{ min, max, mean, median }` for numerics, top-k for categoricals, ISO range for dates). Available before any ask().
275+
- **`annotations`**: Merged `initialAnnotations` + latest AI response. Wire to the chart's `annotations` prop for visual highlighting.
276+
- **`summarizeData(data, options?)`**: Standalone for server-side prompting or batch jobs.
277+
- **MCP Tool**: `interrogateChart(component, props, query)` returns the same statistical summary and AI-facing instructions.
278+
279+
```jsx
280+
import { LineChart, useChartInterrogation } from "semiotic/ai"
281+
282+
function InterrogatableChart({ data }) {
283+
const { ask, history, annotations, loading } = useChartInterrogation({
284+
data,
285+
componentName: "LineChart",
286+
props: { xAccessor: "month", yAccessor: "revenue" },
287+
onQuery: async (query, { summary }) => {
288+
const res = await myLLMCall(query, summary)
289+
return { answer: res.text, annotations: res.highlights }
290+
},
291+
})
292+
return (
293+
<>
294+
<LineChart data={data} xAccessor="month" yAccessor="revenue" annotations={annotations} />
295+
<YourChatUI history={history} loading={loading} onAsk={ask} />
296+
</>
297+
)
298+
}
299+
```
300+
301+
### Chart Capability Layer (`semiotic/ai`)
302+
Heuristic chart-suggestion engine. Charts ship capability descriptors next to their TSX files; the engine ranks them against a profiled dataset by intent. No LLM call required.
303+
304+
- **`profileData(data, { rawInput?, seriesField? })`** → `ChartDataProfile` (extends `DataSummary`): candidate fields per role (x/y/series/category/size/time), distinct counts, monotonicity, structure detection (hierarchy/network/geo).
305+
- **`suggestCharts(data, { intent?, allow?, deny?, maxResults?, includeVariants?, minScore? })`** → ranked `Suggestion[]` with `{ component, family, importPath, variant?, score, intentScores, rubric, reasons, caveats, props }`. `props` is spreadable directly into the matching chart.
306+
- **`scoreChart(component, data, { intent?, variantKey? })`** → evaluate a specific chart for a dataset (does it fit, how well, why/why not).
307+
- **`useChartSuggestions(data, options)`** → memoized React hook returning `{ suggestions, profile }`.
308+
- **`registerChartCapability(capability)`** / **`unregisterChartCapability(name)`** — runtime registration for custom charts.
309+
- **Intent taxonomy**: 13 built-in intents (`trend`, `compare-series`, `compare-categories`, `rank`, `part-to-whole`, `distribution`, `correlation`, `flow`, `hierarchy`, `geo`, `outlier-detection`, `composition-over-time`, `change-detection`). Extend via `registerIntent(descriptor)`.
310+
- **Capability authoring**: create `Foo.capability.ts` next to `Foo.tsx`, then append to the registry in `src/components/ai/chartCapabilities.ts`. Each capability declares `family`, `rubric` (familiarity/accuracy/precision 1-5), `fits(profile)` gate, `intentScores`, optional `variants` with `intentDeltas`, and `buildProps(profile, variant)`.
311+
- **Variants encode that settings change what a chart is good for**: e.g. `StackedAreaChart`'s `streamgraph` variant boosts trend but penalizes part-to-whole.
312+
- **Interrogation tie-in**: pass `includeSuggestions: true` to `useChartInterrogation` and the same ranked list lands in `context.suggestions` for the LLM.
313+
- **MCP tool**: `suggestCharts(data, intent?)` returns the ranked list as structured content.
314+
315+
```jsx
316+
import { useChartSuggestions, LineChart, BarChart, /* ... */ } from "semiotic/ai"
317+
318+
const COMPONENT_MAP = { LineChart, BarChart, /* ... */ }
319+
function SuggestedChart({ data, intent }) {
320+
const { suggestions } = useChartSuggestions(data, { intent })
321+
const top = suggestions[0]
322+
if (!top) return null
323+
const Component = COMPONENT_MAP[top.component]
324+
return <Component {...top.props} />
325+
}
326+
```
327+
270328

271329
## AI Behavior Contracts
272330

0 commit comments

Comments
 (0)