@seed-ship/mcp-ui-solid 3.0.5 → 4.0.0
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.
- package/CHANGELOG.md +115 -0
- package/README.md +253 -280
- package/dist/components/ChartJSRenderer.cjs +37 -15
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +37 -15
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/DataPreviewSection.cjs +172 -0
- package/dist/components/DataPreviewSection.cjs.map +1 -0
- package/dist/components/DataPreviewSection.d.ts +19 -0
- package/dist/components/DataPreviewSection.d.ts.map +1 -0
- package/dist/components/DataPreviewSection.js +172 -0
- package/dist/components/DataPreviewSection.js.map +1 -0
- package/dist/components/MapRenderer.cjs +168 -26
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts +2 -2
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js +169 -27
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +74 -0
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.d.ts.map +1 -1
- package/dist/components/ScratchpadPanel.js +75 -1
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/components/VerifiedText.cjs +166 -0
- package/dist/components/VerifiedText.cjs.map +1 -0
- package/dist/components/VerifiedText.d.ts +22 -0
- package/dist/components/VerifiedText.d.ts.map +1 -0
- package/dist/components/VerifiedText.js +166 -0
- package/dist/components/VerifiedText.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components.cjs +4 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +4 -0
- package/dist/components.d.ts +4 -0
- package/dist/components.js +4 -0
- package/dist/components.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useDataValidator.cjs +31 -0
- package/dist/hooks/useDataValidator.cjs.map +1 -0
- package/dist/hooks/useDataValidator.d.ts +42 -0
- package/dist/hooks/useDataValidator.d.ts.map +1 -0
- package/dist/hooks/useDataValidator.js +31 -0
- package/dist/hooks/useDataValidator.js.map +1 -0
- package/dist/hooks.cjs +2 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +2 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.js +2 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.cjs +290 -0
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.js +291 -0
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.cjs +243 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.js +243 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.js.map +1 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.cjs +137 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.cjs.map +1 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.js +137 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.js.map +1 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.cjs +686 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.js +687 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.js.map +1 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.cjs +1366 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.js +1366 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.cjs +54 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.js +55 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.js.map +1 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.cjs +1256 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.js +1256 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.js.map +1 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.cjs +47 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.js +48 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.js.map +1 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.cjs +378 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.js +379 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.js.map +1 -0
- package/dist/services/data-validator.cjs +85 -0
- package/dist/services/data-validator.cjs.map +1 -0
- package/dist/services/data-validator.d.ts +28 -0
- package/dist/services/data-validator.d.ts.map +1 -0
- package/dist/services/data-validator.js +85 -0
- package/dist/services/data-validator.js.map +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/types/chat-bus.d.ts +88 -1
- package/dist/types/chat-bus.d.ts.map +1 -1
- package/dist/types/index.d.ts +135 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +135 -6
- package/dist/types.d.ts +135 -6
- package/package.json +5 -1
- package/src/components/ChartJSRenderer.tsx +35 -13
- package/src/components/DataPreviewSection.tsx +206 -0
- package/src/components/MapRenderer.test.tsx +94 -5
- package/src/components/MapRenderer.tsx +246 -45
- package/src/components/ScratchpadPanel.tsx +10 -2
- package/src/components/VerifiedText.tsx +187 -0
- package/src/components/index.ts +7 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useDataValidator.ts +68 -0
- package/src/index.ts +26 -1
- package/src/services/data-validator.test.ts +151 -0
- package/src/services/data-validator.ts +149 -0
- package/src/services/index.ts +2 -0
- package/src/types/chat-bus.ts +98 -1
- package/src/types/index.ts +145 -6
- package/tsconfig.tsbuildinfo +1 -1
package/README.md
CHANGED
|
@@ -5,17 +5,15 @@ SolidJS components + chat toolkit for MCP-generated UI. Part of the [MCP UI ecos
|
|
|
5
5
|
[](https://www.npmjs.com/package/@seed-ship/mcp-ui-solid)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
## What's New in
|
|
9
|
-
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **Preview auto-refresh** - `previewEndpoint` + configurable method/headers + debounce
|
|
18
|
-
- **Chat Bus** (`@experimental`) - Bidirectional event/command bus (18 events, 11 commands)
|
|
8
|
+
## What's New in v4.0.0
|
|
9
|
+
|
|
10
|
+
- **Data Verification Layer** - Anti-hallucination: `validateAgainstSource()` detects ~90% of numerical hallucinations, zero LLM cost, <1ms
|
|
11
|
+
- **VerifiedText component** - Inline badges (verified/hallucinated) with highlight, strip, annotate modes
|
|
12
|
+
- **DataPreviewSection** - Paginated data table with CSV/JSON export, source attribution, FR locale formatting
|
|
13
|
+
- **GeoJSON maps** - Polygon/line/point rendering, choropleth coloring, feature popups, multi-layer support
|
|
14
|
+
- **PMTiles** - Vector tiles for large datasets (>5000 features) via optional `protomaps-leaflet`
|
|
15
|
+
- **Time-series charts** - `timeAxis` config for date-based x-axis in ChartJSRenderer
|
|
16
|
+
- **18 scratchpad section types** - Added verified_text, data_preview, map, chart (was 14)
|
|
19
17
|
- **19 component renderers** - chart, table, metric, code, map, form, modal, gallery, video, iframe + more
|
|
20
18
|
|
|
21
19
|
## Installation
|
|
@@ -28,6 +26,14 @@ npm install @seed-ship/mcp-ui-solid
|
|
|
28
26
|
|
|
29
27
|
**Peer dependencies:** `solid-js` ^1.9.0
|
|
30
28
|
|
|
29
|
+
**Optional peer deps** (install as needed):
|
|
30
|
+
- `chart.js` — native chart rendering
|
|
31
|
+
- `leaflet` + `leaflet.markercluster` — maps
|
|
32
|
+
- `highlight.js` — code syntax highlighting
|
|
33
|
+
- `protomaps-leaflet` — PMTiles vector tiles
|
|
34
|
+
- `@duckdb/duckdb-wasm` — DuckDB plugin
|
|
35
|
+
- `@tanstack/solid-virtual` — table virtualization
|
|
36
|
+
|
|
31
37
|
## Quick Start
|
|
32
38
|
|
|
33
39
|
### Static UI Rendering
|
|
@@ -76,6 +82,163 @@ function StreamingDashboard() {
|
|
|
76
82
|
}
|
|
77
83
|
```
|
|
78
84
|
|
|
85
|
+
## Data Verification — Anti-Hallucination (v4.0.0)
|
|
86
|
+
|
|
87
|
+
### validateAgainstSource — Pure function
|
|
88
|
+
|
|
89
|
+
Detects numerical hallucinations by comparing LLM text against source data. Zero dependencies, <1ms.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { validateAgainstSource } from '@seed-ship/mcp-ui-solid'
|
|
93
|
+
|
|
94
|
+
const rows = [
|
|
95
|
+
{ type: 'Appartement', ventes: 22306, prix_m2: 3337 },
|
|
96
|
+
{ type: 'Maison', ventes: 2492, prix_m2: 4230 },
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
const result = validateAgainstSource(
|
|
100
|
+
"On observe 22 306 ventes a 3 337 EUR/m2. En 2023, 18 245 ventes.",
|
|
101
|
+
rows
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
// result.valid === false
|
|
105
|
+
// result.hallucinated === [{ value: 18245, closest: 22306, distance: 0.18 }]
|
|
106
|
+
// result.confidence === 0.67
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Options: `tolerance` (default 1%), `ignoreColumns`, `ignorePatterns` (years, postal codes ignored by default).
|
|
110
|
+
|
|
111
|
+
### useDataValidator — Reactive hook
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { useDataValidator } from '@seed-ship/mcp-ui-solid'
|
|
115
|
+
|
|
116
|
+
const { valid, confidence, hallucinatedCount } = useDataValidator(
|
|
117
|
+
() => llmText(),
|
|
118
|
+
() => sourceRows(),
|
|
119
|
+
{ tolerance: 0.02 }
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### VerifiedText — Inline badges
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { VerifiedText } from '@seed-ship/mcp-ui-solid'
|
|
127
|
+
|
|
128
|
+
<VerifiedText
|
|
129
|
+
text={llmResponse}
|
|
130
|
+
validation={validationResult}
|
|
131
|
+
mode="highlight" // or "strip" | "annotate"
|
|
132
|
+
onHallucinationClick={(item) => console.log('Hallucinated:', item)}
|
|
133
|
+
/>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### DataPreviewSection — Source data table
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { DataPreviewSection } from '@seed-ship/mcp-ui-solid'
|
|
140
|
+
|
|
141
|
+
<DataPreviewSection content={{
|
|
142
|
+
columns: [
|
|
143
|
+
{ key: 'type', label: 'Type', type: 'string' },
|
|
144
|
+
{ key: 'ventes', label: 'Ventes', type: 'number' },
|
|
145
|
+
{ key: 'prix_m2', label: 'Prix moy. EUR/m2', type: 'number' },
|
|
146
|
+
],
|
|
147
|
+
rows: sourceRows,
|
|
148
|
+
source: 'data.gouv.fr - Stats DVF',
|
|
149
|
+
freshness: 'Donnees 2025',
|
|
150
|
+
exportable: true,
|
|
151
|
+
pageSize: 25,
|
|
152
|
+
}} />
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## GeoJSON Maps (v4.0.0)
|
|
156
|
+
|
|
157
|
+
### GeoJSON + Choropleth + Popups
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { MapRenderer } from '@seed-ship/mcp-ui-solid'
|
|
161
|
+
|
|
162
|
+
<MapRenderer params={{
|
|
163
|
+
geojson: featureCollection,
|
|
164
|
+
geojsonStyle: {
|
|
165
|
+
choroplethField: 'prix_m2',
|
|
166
|
+
choroplethScale: [
|
|
167
|
+
[2000, '#eff3ff'],
|
|
168
|
+
[3000, '#6baed6'],
|
|
169
|
+
[5000, '#084594'],
|
|
170
|
+
],
|
|
171
|
+
fillOpacity: 0.7,
|
|
172
|
+
},
|
|
173
|
+
popup: {
|
|
174
|
+
titleField: 'name',
|
|
175
|
+
fields: ['prix_m2', 'ventes'],
|
|
176
|
+
},
|
|
177
|
+
fitBounds: true,
|
|
178
|
+
height: '500px',
|
|
179
|
+
}} />
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Multi-layer Maps
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
<MapRenderer params={{
|
|
186
|
+
layers: [
|
|
187
|
+
{ name: 'Parcelles', geojson: parcelles, visible: true,
|
|
188
|
+
style: { choroplethField: 'prix', choroplethScale: [[100, '#fee'], [500, '#c00']] } },
|
|
189
|
+
{ name: 'Risques', geojson: risques, visible: false,
|
|
190
|
+
style: { fillColor: 'orange', fillOpacity: 0.3 } },
|
|
191
|
+
],
|
|
192
|
+
fitBounds: true,
|
|
193
|
+
}} />
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### PMTiles — Large Datasets
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
<MapRenderer params={{
|
|
200
|
+
pmtiles: {
|
|
201
|
+
url: 'https://cdn.example.com/data.pmtiles',
|
|
202
|
+
paintRules: [
|
|
203
|
+
{ dataLayer: 'buildings', symbolizer: 'polygon', color: '#3388ff', opacity: 0.6 },
|
|
204
|
+
],
|
|
205
|
+
maxZoom: 16,
|
|
206
|
+
},
|
|
207
|
+
center: [43.6, 3.87],
|
|
208
|
+
zoom: 12,
|
|
209
|
+
}} />
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Requires `protomaps-leaflet` peer dependency.
|
|
213
|
+
|
|
214
|
+
## Time-Series Charts (v4.0.0)
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
<ChartJSRenderer component={{
|
|
218
|
+
id: 'ndvi-timeline',
|
|
219
|
+
type: 'chart',
|
|
220
|
+
position: { colStart: 1, colSpan: 12 },
|
|
221
|
+
params: {
|
|
222
|
+
type: 'line',
|
|
223
|
+
data: {
|
|
224
|
+
labels: ['2024-01-15', '2024-02-15', '2024-03-15', '2024-04-15'],
|
|
225
|
+
datasets: [{
|
|
226
|
+
label: 'NDVI',
|
|
227
|
+
data: [0.45, 0.42, 0.55, 0.68],
|
|
228
|
+
borderColor: '#10b981',
|
|
229
|
+
fill: true,
|
|
230
|
+
tension: 0.3,
|
|
231
|
+
}],
|
|
232
|
+
},
|
|
233
|
+
timeAxis: {
|
|
234
|
+
unit: 'month',
|
|
235
|
+
tooltipFormat: 'MMM yyyy',
|
|
236
|
+
},
|
|
237
|
+
exportable: true,
|
|
238
|
+
},
|
|
239
|
+
}} />
|
|
240
|
+
```
|
|
241
|
+
|
|
79
242
|
## Chat Bus — Agent Interactions (`@experimental`)
|
|
80
243
|
|
|
81
244
|
Bidirectional event/command system for agent-driven chat interactions. Your app keeps full control of its chat UI — the bus adds structured interactivity on top.
|
|
@@ -83,20 +246,20 @@ Bidirectional event/command system for agent-driven chat interactions. Your app
|
|
|
83
246
|
### Architecture
|
|
84
247
|
|
|
85
248
|
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
events
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
249
|
+
+----------------------+
|
|
250
|
+
| AGENT LAYER |
|
|
251
|
+
| (your app logic) |
|
|
252
|
+
+--+----------+-------+
|
|
253
|
+
events | | commands
|
|
254
|
+
v v
|
|
255
|
+
+--------------------------------------------------+
|
|
256
|
+
| Chat Messages (your app renders these) |
|
|
257
|
+
| + UIResourceRenderer for MCP components |
|
|
258
|
+
+--------------------------------------------------+
|
|
259
|
+
| ChatPrompt (MCP-UI) - choice | confirm | form |
|
|
260
|
+
+--------------------------------------------------+
|
|
261
|
+
| Chat Input (your app controls this) |
|
|
262
|
+
+--------------------------------------------------+
|
|
100
263
|
```
|
|
101
264
|
|
|
102
265
|
### Usage
|
|
@@ -119,285 +282,88 @@ function ChatInterface() {
|
|
|
119
282
|
const bus = useChatBus()
|
|
120
283
|
const [activePrompt, setActivePrompt] = createSignal(null)
|
|
121
284
|
|
|
122
|
-
// Bridge SSE → bus events
|
|
123
285
|
onSSEEvent('done', (data) =>
|
|
124
286
|
bus.events.emit('onStreamEnd', { streamKey: 'main', metadata: data }))
|
|
125
|
-
onSSEEvent('ui_layout', (data) =>
|
|
126
|
-
bus.events.emit('onUILayout', { streamKey: 'main', layout: data }))
|
|
127
287
|
|
|
128
|
-
// Handle commands from agents
|
|
129
288
|
bus.commands.handle('injectPrompt', (text) => setInputValue(text))
|
|
130
|
-
bus.commands.handle('sendPrompt', (text) => {
|
|
131
|
-
setInputValue(text); handleSend(); return crypto.randomUUID()
|
|
132
|
-
})
|
|
133
289
|
bus.commands.handle('showChatPrompt', (config) => setActivePrompt(config))
|
|
134
290
|
|
|
135
291
|
return (
|
|
136
292
|
<div>
|
|
137
293
|
<Messages />
|
|
138
294
|
<Show when={activePrompt()}>
|
|
139
|
-
<ChatPrompt
|
|
140
|
-
config={activePrompt()!}
|
|
141
|
-
onSubmit={(response) => {
|
|
142
|
-
bus.events.emit('onChatPromptResponse', { streamKey: 'main', response })
|
|
143
|
-
setActivePrompt(null)
|
|
144
|
-
}}
|
|
145
|
-
onDismiss={() => setActivePrompt(null)}
|
|
146
|
-
/>
|
|
295
|
+
<ChatPrompt config={activePrompt()!} onSubmit={handleResponse} onDismiss={() => setActivePrompt(null)} />
|
|
147
296
|
</Show>
|
|
148
297
|
<TextInput />
|
|
149
298
|
</div>
|
|
150
299
|
)
|
|
151
300
|
}
|
|
152
|
-
|
|
153
|
-
// 3. Agents react to events and emit commands
|
|
154
|
-
function AgentRouter() {
|
|
155
|
-
const bus = useChatBus()
|
|
156
|
-
|
|
157
|
-
bus.events.on('onStreamEnd', (event) => {
|
|
158
|
-
if (event.metadata.needs_clarification) {
|
|
159
|
-
bus.commands.exec('showChatPrompt', {
|
|
160
|
-
type: 'choice',
|
|
161
|
-
title: 'Which period?',
|
|
162
|
-
config: { options: [{ value: '2024', label: '2024' }, { value: '2025', label: '2025' }] }
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
return null
|
|
168
|
-
}
|
|
169
301
|
```
|
|
170
302
|
|
|
171
|
-
### Event Types (
|
|
172
|
-
|
|
173
|
-
| Event | Payload | Description |
|
|
174
|
-
|-------|---------|-------------|
|
|
175
|
-
| `onToken` | `{ token }` | Streaming text token (use throttle) |
|
|
176
|
-
| `onStreamStart` | `{}` | Stream started |
|
|
177
|
-
| `onStreamEnd` | `{ metadata }` | Stream completed with metadata |
|
|
178
|
-
| `onError` | `{ error }` | Stream error |
|
|
179
|
-
| `onUILayout` | `{ layout }` | MCP UI component to render |
|
|
180
|
-
| `onCitation` | `{ citation }` | Citation reference |
|
|
181
|
-
| `onToolCall` | `{ tool }` | Tool execution status |
|
|
182
|
-
| `onSuggestions` | `{ items }` | Suggestion chips |
|
|
183
|
-
| `onChatPromptResponse` | `{ response }` | User responded to ChatPrompt |
|
|
184
|
-
| `onClarificationNeeded` | `{ clarification }` | Needs user clarification |
|
|
185
|
-
| `onAgentSwitch` | `{ agent }` | Active agent changed |
|
|
186
|
-
| `onBriefing` | `{ briefing }` | Briefing update |
|
|
187
|
-
| `onCapabilityChange` | `{ capabilities }` | Agent capabilities changed |
|
|
188
|
-
| `onCustomEvent` | `{ type, data }` | App-specific event |
|
|
189
|
-
|
|
190
|
-
All events carry `ChatEventBase` (`streamKey`, `conversationId?`, `correlationId?`) for multi-stream support.
|
|
191
|
-
|
|
192
|
-
### Command Types (10)
|
|
193
|
-
|
|
194
|
-
| Command | Args | Returns | Description |
|
|
195
|
-
|---------|------|---------|-------------|
|
|
196
|
-
| `injectPrompt` | `text` | void | Fill input without sending |
|
|
197
|
-
| `sendPrompt` | `text, metadata?` | `correlationId` | Fill + send, returns correlation ID |
|
|
198
|
-
| `appendPrompt` | `text` | void | Append to current input |
|
|
199
|
-
| `showChatPrompt` | `config, signal?` | `Promise<Response>` | Show structured prompt (AbortSignal for cleanup) |
|
|
200
|
-
| `dismissChatPrompt` | — | void | Close active prompt |
|
|
201
|
-
| `showSuggestions` | `items` | void | Show suggestion chips |
|
|
202
|
-
| `toggleConnector` | `id, enabled` | void | Toggle a connector |
|
|
203
|
-
| `setMode` | `mode` | void | Change chat mode |
|
|
204
|
-
| `scrollToMessage` | `messageId` | void | Scroll to message |
|
|
205
|
-
| `notify` | `message, type?` | void | Show notification |
|
|
206
|
-
|
|
207
|
-
### Throttle + StreamKey Filtering
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
// Throttle hot-path events (recommended for onToken)
|
|
211
|
-
bus.events.on('onToken', handler, { throttle: 100 })
|
|
212
|
-
|
|
213
|
-
// Filter by stream (multi-stream support)
|
|
214
|
-
bus.events.on('onStreamEnd', handler, { streamKey: 'stream-1' })
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## ChatPrompt — Structured Interactions (`@experimental`)
|
|
218
|
-
|
|
219
|
-
Three subtypes for common agent interaction patterns:
|
|
303
|
+
### Event Types (18) / Command Types (11)
|
|
220
304
|
|
|
221
|
-
|
|
222
|
-
// Choice — buttons with optional icons and descriptions
|
|
223
|
-
<ChatPrompt config={{
|
|
224
|
-
type: 'choice',
|
|
225
|
-
title: 'Export format?',
|
|
226
|
-
config: {
|
|
227
|
-
options: [
|
|
228
|
-
{ value: 'pdf', label: 'PDF', icon: '📄' },
|
|
229
|
-
{ value: 'csv', label: 'CSV', icon: '📊', description: 'Raw data' },
|
|
230
|
-
],
|
|
231
|
-
layout: 'horizontal', // or 'vertical' | 'grid'
|
|
232
|
-
}
|
|
233
|
-
}} onSubmit={handleResponse} />
|
|
234
|
-
|
|
235
|
-
// Confirm — with danger variant
|
|
236
|
-
<ChatPrompt config={{
|
|
237
|
-
type: 'confirm',
|
|
238
|
-
title: 'Delete 47 documents?',
|
|
239
|
-
config: { message: 'This cannot be undone.', confirmLabel: 'Delete', variant: 'danger' }
|
|
240
|
-
}} onSubmit={handleResponse} />
|
|
241
|
-
|
|
242
|
-
// Form — quick fields with validation
|
|
243
|
-
<ChatPrompt config={{
|
|
244
|
-
type: 'form',
|
|
245
|
-
title: 'Additional info',
|
|
246
|
-
config: {
|
|
247
|
-
fields: [
|
|
248
|
-
{ name: 'title', label: 'Title', type: 'text', required: true },
|
|
249
|
-
{ name: 'category', label: 'Category', type: 'select',
|
|
250
|
-
options: [{ label: 'Report', value: 'report' }] },
|
|
251
|
-
],
|
|
252
|
-
submitLabel: 'Send',
|
|
253
|
-
}
|
|
254
|
-
}} onSubmit={handleResponse} />
|
|
255
|
-
|
|
256
|
-
// Multi-select — dropdown checkboxes + chips (v2.6.0)
|
|
257
|
-
<ChatPrompt config={{
|
|
258
|
-
type: 'form',
|
|
259
|
-
title: 'DVF Parameters',
|
|
260
|
-
config: {
|
|
261
|
-
fields: [
|
|
262
|
-
{ name: 'years', label: 'Years', type: 'select', multiple: true,
|
|
263
|
-
options: [{ label: '2024', value: '2024' }, { label: '2023', value: '2023' }, { label: '2022', value: '2022' }] },
|
|
264
|
-
],
|
|
265
|
-
submitLabel: 'Search',
|
|
266
|
-
}
|
|
267
|
-
}} onSubmit={handleResponse} />
|
|
268
|
-
// → response.value = { years: ["2024", "2023"] }
|
|
269
|
-
|
|
270
|
-
// Autocomplete — API fetch for large datasets (v2.6.0)
|
|
271
|
-
<ChatPrompt config={{
|
|
272
|
-
type: 'form',
|
|
273
|
-
title: 'Select commune',
|
|
274
|
-
config: {
|
|
275
|
-
fields: [
|
|
276
|
-
{ name: 'commune', label: 'Commune', type: 'autocomplete',
|
|
277
|
-
apiUrl: 'https://geo.api.gouv.fr/communes', searchParam: 'nom',
|
|
278
|
-
labelField: 'nom', valueField: 'code',
|
|
279
|
-
extraParams: { fields: 'nom,code', limit: '10' }, minChars: 2 },
|
|
280
|
-
],
|
|
281
|
-
submitLabel: 'Search',
|
|
282
|
-
}
|
|
283
|
-
}} onSubmit={handleResponse} />
|
|
284
|
-
// → type "Mont" → dropdown [Montpellier, Montreuil, ...]
|
|
285
|
-
// → response.value = { commune: "34172" }
|
|
286
|
-
```
|
|
305
|
+
See [Chat Bus documentation](https://github.com/theseedship/mcp-ui#chat-bus--agent-interactions-experimental) for the full event/command reference.
|
|
287
306
|
|
|
288
307
|
## ScratchpadPanel — HITL/AITL Shared Workspace (`@experimental`)
|
|
289
308
|
|
|
290
|
-
A shared workspace where agent and human collaborate in real-time.
|
|
309
|
+
A shared workspace where agent and human collaborate in real-time. 18 section types:
|
|
310
|
+
|
|
311
|
+
| Type | Renders | Use case |
|
|
312
|
+
|------|---------|----------|
|
|
313
|
+
| `data` | Key-value pairs | Dataset info |
|
|
314
|
+
| `filter` | Editable chips | Active filters |
|
|
315
|
+
| `preview` | Count + mini-table | Live result count |
|
|
316
|
+
| `message` | Agent bubble | Explanations |
|
|
317
|
+
| `action` | Buttons | Validate, refine |
|
|
318
|
+
| `steps` | Stepper | Guided workflow |
|
|
319
|
+
| `form` | FormFieldRenderer | Interactive params |
|
|
320
|
+
| `understanding` | Confidence badges | Agent comprehension |
|
|
321
|
+
| `feedback` | Thumbs up/down | User validation |
|
|
322
|
+
| `prompt` | Query + params | Agent interpretation |
|
|
323
|
+
| `stepper` | Progress stepper | Multi-turn progress |
|
|
324
|
+
| `error` | Error card | Error display + retry |
|
|
325
|
+
| `source_card` | Source info card | Data source details |
|
|
326
|
+
| `diff` | Before/after diff | Change preview |
|
|
327
|
+
| `verified_text` | Inline badges | Data verification |
|
|
328
|
+
| `data_preview` | Paginated table | Source data display |
|
|
329
|
+
| `map` | GeoJSON map | Geographic data |
|
|
330
|
+
| `chart` | Chart.js chart | Time-series, analytics |
|
|
331
|
+
|
|
332
|
+
### Direct store (recommended)
|
|
291
333
|
|
|
292
334
|
```tsx
|
|
293
|
-
import {
|
|
294
|
-
import type { ScratchpadState } from '@seed-ship/mcp-ui-solid'
|
|
295
|
-
|
|
296
|
-
function WorkspaceView() {
|
|
297
|
-
const [state, setState] = createSignal<ScratchpadState>(/* from SSE */)
|
|
335
|
+
import { dispatchScratchpad, useScratchpadState } from '@seed-ship/mcp-ui-solid'
|
|
298
336
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (event.scratchpad.action === 'create') setState(event.scratchpad)
|
|
302
|
-
if (event.scratchpad.action === 'update') setState(prev => ({ ...prev, ...event.scratchpad }))
|
|
303
|
-
})
|
|
337
|
+
// In your SSE callback — ONE LINE
|
|
338
|
+
onScratchpad: (data) => dispatchScratchpad(data as ScratchpadEvent)
|
|
304
339
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
state={state()}
|
|
308
|
-
onFilterChange={(filters) => {
|
|
309
|
-
// Send updated filters to agent
|
|
310
|
-
fetch('/api/chat-stream/scratchpad-update', {
|
|
311
|
-
method: 'POST',
|
|
312
|
-
body: JSON.stringify({ id: state().id, filters })
|
|
313
|
-
})
|
|
314
|
-
}}
|
|
315
|
-
onAction={(action) => {
|
|
316
|
-
if (action === 'validate') bus.commands.exec('sendPrompt', 'Valider et synthetiser')
|
|
317
|
-
}}
|
|
318
|
-
/>
|
|
319
|
-
)
|
|
320
|
-
}
|
|
340
|
+
// In your component
|
|
341
|
+
const { state, pinned, close } = useScratchpadState()
|
|
321
342
|
```
|
|
322
343
|
|
|
323
|
-
### Section Types
|
|
324
|
-
|
|
325
|
-
| Type | Renders | Editable | Use case |
|
|
326
|
-
|------|---------|:--------:|----------|
|
|
327
|
-
| `data` | Key-value pairs | No | Dataset info, column list |
|
|
328
|
-
| `filter` | Editable chips + remove | Yes | Active filters (dept, year) |
|
|
329
|
-
| `preview` | Count badge + summary + mini-table | No | Live result count |
|
|
330
|
-
| `message` | Agent bubble (info/question/warning) | No | Agent explanations |
|
|
331
|
-
| `action` | Buttons (primary/danger/default) | No | Validate, refine, change |
|
|
332
|
-
| `steps` | Stepper with embedded content | No | Guided workflow |
|
|
333
|
-
| `form` | Full FormFieldRenderer (select, autocomplete, depends_on) | Yes | Interactive parameters |
|
|
334
|
-
| `understanding` | Confidence badges (high/medium/low) + warnings | No | Agent comprehension display |
|
|
335
|
-
| `feedback` | Thumbs up/down + optional comment | Yes | Validate/reject agent approach |
|
|
336
|
-
| `prompt` | Original query + extracted params + plan | Optional | Agent interpretation |
|
|
337
|
-
|
|
338
|
-
### Status Badges
|
|
339
|
-
|
|
340
|
-
`loading` → `ready` → `waiting_human` (pulsing) → `processing` → `complete`
|
|
341
|
-
|
|
342
344
|
## Component Renderers (19 types)
|
|
343
345
|
|
|
344
|
-
| Type |
|
|
345
|
-
|
|
346
|
-
| `chart` |
|
|
347
|
-
| `table` |
|
|
348
|
-
| `metric` |
|
|
349
|
-
| `text` |
|
|
350
|
-
| `code` |
|
|
351
|
-
| `map` |
|
|
352
|
-
| `form` |
|
|
353
|
-
| `modal` |
|
|
354
|
-
| `image-gallery` |
|
|
355
|
-
| `video` |
|
|
356
|
-
| `iframe` |
|
|
357
|
-
| `image` |
|
|
358
|
-
| `link` |
|
|
359
|
-
| `action` |
|
|
360
|
-
| `action-group` |
|
|
361
|
-
| `grid` |
|
|
362
|
-
| `carousel` |
|
|
363
|
-
| `artifact` |
|
|
364
|
-
| `footer` |
|
|
365
|
-
|
|
366
|
-
All wrapped with `ExpandableWrapper` (fullscreen expand via DOM reparenting) where applicable.
|
|
367
|
-
|
|
368
|
-
## Iframe Security
|
|
369
|
-
|
|
370
|
-
Tiered sandbox system — trusted domains get `allow-same-origin`, untrusted get restrictive sandbox:
|
|
371
|
-
|
|
372
|
-
```typescript
|
|
373
|
-
import { getIframeSandbox, DEFAULT_IFRAME_DOMAINS, TRUSTED_IFRAME_DOMAINS } from '@seed-ship/mcp-ui-solid'
|
|
374
|
-
|
|
375
|
-
// Automatic — IframeRenderer uses getIframeSandbox() internally
|
|
376
|
-
// Manual usage:
|
|
377
|
-
const sandbox = getIframeSandbox('https://docs.google.com/spreadsheets/...')
|
|
378
|
-
// → "allow-scripts allow-popups allow-same-origin allow-forms" (trusted)
|
|
379
|
-
|
|
380
|
-
const sandbox2 = getIframeSandbox('https://quickchart.io/chart?...')
|
|
381
|
-
// → "allow-scripts allow-popups" (untrusted — no same-origin)
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
**80+ whitelisted domains** including: Google services, YouTube, Vimeo, GitHub, Figma, Notion, Stripe, Polar.sh, HubSpot, data.gouv.fr, and more.
|
|
385
|
-
|
|
386
|
-
## Validation
|
|
387
|
-
|
|
388
|
-
All 19 component types validated, including:
|
|
389
|
-
- **Chart**: scatter/bubble (no labels required), time-series `{x,y}`, data type validation
|
|
390
|
-
- **Table**: columns + rows structure
|
|
391
|
-
- **Video**: URL + domain whitelist
|
|
392
|
-
- **Form/Carousel/Gallery/ActionGroup**: non-empty arrays
|
|
393
|
-
- **Code/Map/Artifact**: required content
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
import { validateComponent, validateLayout } from '@seed-ship/mcp-ui-solid'
|
|
397
|
-
|
|
398
|
-
const result = validateComponent(component)
|
|
399
|
-
if (!result.valid) console.error(result.errors)
|
|
400
|
-
```
|
|
346
|
+
| Type | Features |
|
|
347
|
+
|------|----------|
|
|
348
|
+
| `chart` | Bar, line, pie, scatter, bubble, polarArea, time-series. Native Chart.js or Quickchart fallback. PNG export. |
|
|
349
|
+
| `table` | Sortable, pagination, virtualization (10K+), CSV/TSV/JSON export |
|
|
350
|
+
| `metric` | KPI cards with trends and sparklines |
|
|
351
|
+
| `text` | Markdown via marked.js |
|
|
352
|
+
| `code` | Syntax highlighting (highlight.js), line numbers, word wrap |
|
|
353
|
+
| `map` | Leaflet: markers, clustering, GeoJSON, choropleth, popups, multi-layer, PMTiles |
|
|
354
|
+
| `form` | 18 field types, conditional fields, persistence, tool call submit |
|
|
355
|
+
| `modal` | Portal overlay, sizes sm-full, Escape/backdrop close |
|
|
356
|
+
| `image-gallery` | Grid layout, lightbox, keyboard nav |
|
|
357
|
+
| `video` | YouTube/Vimeo/direct URL |
|
|
358
|
+
| `iframe` | Tiered sandbox, 80+ whitelisted domains |
|
|
359
|
+
| `image` | Responsive with lazy loading |
|
|
360
|
+
| `link` | Styled link cards |
|
|
361
|
+
| `action` | Tool call buttons |
|
|
362
|
+
| `action-group` | Grouped actions with layout options |
|
|
363
|
+
| `grid` | Nested 12-column CSS Grid |
|
|
364
|
+
| `carousel` | Content carousel |
|
|
365
|
+
| `artifact` | File download/preview |
|
|
366
|
+
| `footer` | Metadata display |
|
|
401
367
|
|
|
402
368
|
## SSR Compatibility
|
|
403
369
|
|
|
@@ -415,27 +381,34 @@ export default defineConfig({
|
|
|
415
381
|
// Components
|
|
416
382
|
import {
|
|
417
383
|
UIResourceRenderer, StreamingUIRenderer, GenerativeUIErrorBoundary,
|
|
418
|
-
ExpandableWrapper, ComponentToolbar,
|
|
384
|
+
ExpandableWrapper, ComponentToolbar,
|
|
385
|
+
ChatPrompt, ScratchpadPanel,
|
|
386
|
+
VerifiedText, DataPreviewSection,
|
|
419
387
|
} from '@seed-ship/mcp-ui-solid'
|
|
420
388
|
|
|
389
|
+
// Data Verification
|
|
390
|
+
import { validateAgainstSource } from '@seed-ship/mcp-ui-solid'
|
|
391
|
+
import { useDataValidator } from '@seed-ship/mcp-ui-solid'
|
|
392
|
+
|
|
421
393
|
// Chat Bus
|
|
422
394
|
import {
|
|
423
395
|
ChatBusProvider, useChatBus,
|
|
396
|
+
dispatchScratchpad, useScratchpadState,
|
|
424
397
|
createChatBus, createEventEmitter, createCommandHandler,
|
|
425
398
|
} from '@seed-ship/mcp-ui-solid'
|
|
426
399
|
|
|
427
400
|
// Validation + Security
|
|
428
401
|
import {
|
|
429
|
-
validateComponent, validateLayout,
|
|
402
|
+
validateComponent, validateLayout,
|
|
430
403
|
getIframeSandbox, DEFAULT_IFRAME_DOMAINS, TRUSTED_IFRAME_DOMAINS,
|
|
431
|
-
ComponentRegistry,
|
|
432
404
|
} from '@seed-ship/mcp-ui-solid'
|
|
433
405
|
|
|
434
406
|
// Types
|
|
435
407
|
import type {
|
|
408
|
+
DataValidation, HallucinatedNumber, DataValidationOptions,
|
|
409
|
+
VerifiedTextContent, DataPreviewContent, MapSectionContent,
|
|
410
|
+
MapGeoJSONStyle, MapPopupConfig, MapLayer, MapPMTilesConfig,
|
|
436
411
|
ChatBus, ChatEvents, ChatCommands,
|
|
437
|
-
ChatPromptConfig, ChatPromptResponse,
|
|
438
|
-
AgentContext, BriefingEvent,
|
|
439
412
|
ScratchpadState, ScratchpadSection, ScratchpadEvent,
|
|
440
413
|
UIComponent, UILayout, ComponentType,
|
|
441
414
|
} from '@seed-ship/mcp-ui-solid'
|