@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.
Files changed (126) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +253 -280
  3. package/dist/components/ChartJSRenderer.cjs +37 -15
  4. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  5. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  6. package/dist/components/ChartJSRenderer.js +37 -15
  7. package/dist/components/ChartJSRenderer.js.map +1 -1
  8. package/dist/components/DataPreviewSection.cjs +172 -0
  9. package/dist/components/DataPreviewSection.cjs.map +1 -0
  10. package/dist/components/DataPreviewSection.d.ts +19 -0
  11. package/dist/components/DataPreviewSection.d.ts.map +1 -0
  12. package/dist/components/DataPreviewSection.js +172 -0
  13. package/dist/components/DataPreviewSection.js.map +1 -0
  14. package/dist/components/MapRenderer.cjs +168 -26
  15. package/dist/components/MapRenderer.cjs.map +1 -1
  16. package/dist/components/MapRenderer.d.ts +2 -2
  17. package/dist/components/MapRenderer.d.ts.map +1 -1
  18. package/dist/components/MapRenderer.js +169 -27
  19. package/dist/components/MapRenderer.js.map +1 -1
  20. package/dist/components/ScratchpadPanel.cjs +74 -0
  21. package/dist/components/ScratchpadPanel.cjs.map +1 -1
  22. package/dist/components/ScratchpadPanel.d.ts.map +1 -1
  23. package/dist/components/ScratchpadPanel.js +75 -1
  24. package/dist/components/ScratchpadPanel.js.map +1 -1
  25. package/dist/components/VerifiedText.cjs +166 -0
  26. package/dist/components/VerifiedText.cjs.map +1 -0
  27. package/dist/components/VerifiedText.d.ts +22 -0
  28. package/dist/components/VerifiedText.d.ts.map +1 -0
  29. package/dist/components/VerifiedText.js +166 -0
  30. package/dist/components/VerifiedText.js.map +1 -0
  31. package/dist/components/index.d.ts +4 -0
  32. package/dist/components/index.d.ts.map +1 -1
  33. package/dist/components.cjs +4 -0
  34. package/dist/components.cjs.map +1 -1
  35. package/dist/components.d.cts +4 -0
  36. package/dist/components.d.ts +4 -0
  37. package/dist/components.js +4 -0
  38. package/dist/components.js.map +1 -1
  39. package/dist/hooks/index.d.ts +2 -0
  40. package/dist/hooks/index.d.ts.map +1 -1
  41. package/dist/hooks/useDataValidator.cjs +31 -0
  42. package/dist/hooks/useDataValidator.cjs.map +1 -0
  43. package/dist/hooks/useDataValidator.d.ts +42 -0
  44. package/dist/hooks/useDataValidator.d.ts.map +1 -0
  45. package/dist/hooks/useDataValidator.js +31 -0
  46. package/dist/hooks/useDataValidator.js.map +1 -0
  47. package/dist/hooks.cjs +2 -0
  48. package/dist/hooks.cjs.map +1 -1
  49. package/dist/hooks.d.cts +2 -0
  50. package/dist/hooks.d.ts +2 -0
  51. package/dist/hooks.js +2 -0
  52. package/dist/hooks.js.map +1 -1
  53. package/dist/index.cjs +8 -0
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/index.d.cts +9 -5
  56. package/dist/index.d.ts +9 -5
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +8 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.cjs +290 -0
  61. package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.cjs.map +1 -0
  62. package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.js +291 -0
  63. package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.js.map +1 -0
  64. package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.cjs +243 -0
  65. package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.cjs.map +1 -0
  66. package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.js +243 -0
  67. package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.js.map +1 -0
  68. package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.cjs +137 -0
  69. package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.cjs.map +1 -0
  70. package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.js +137 -0
  71. package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.js.map +1 -0
  72. package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.cjs +686 -0
  73. package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.cjs.map +1 -0
  74. package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.js +687 -0
  75. package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.js.map +1 -0
  76. package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.cjs +1366 -0
  77. package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.cjs.map +1 -0
  78. package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.js +1366 -0
  79. package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.js.map +1 -0
  80. package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.cjs +54 -0
  81. package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.cjs.map +1 -0
  82. package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.js +55 -0
  83. package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.js.map +1 -0
  84. package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.cjs +1256 -0
  85. package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.cjs.map +1 -0
  86. package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.js +1256 -0
  87. package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.js.map +1 -0
  88. package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.cjs +47 -0
  89. package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.cjs.map +1 -0
  90. package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.js +48 -0
  91. package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.js.map +1 -0
  92. package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.cjs +378 -0
  93. package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.cjs.map +1 -0
  94. package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.js +379 -0
  95. package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.js.map +1 -0
  96. package/dist/services/data-validator.cjs +85 -0
  97. package/dist/services/data-validator.cjs.map +1 -0
  98. package/dist/services/data-validator.d.ts +28 -0
  99. package/dist/services/data-validator.d.ts.map +1 -0
  100. package/dist/services/data-validator.js +85 -0
  101. package/dist/services/data-validator.js.map +1 -0
  102. package/dist/services/index.d.ts +1 -0
  103. package/dist/services/index.d.ts.map +1 -1
  104. package/dist/types/chat-bus.d.ts +88 -1
  105. package/dist/types/chat-bus.d.ts.map +1 -1
  106. package/dist/types/index.d.ts +135 -6
  107. package/dist/types/index.d.ts.map +1 -1
  108. package/dist/types.d.cts +135 -6
  109. package/dist/types.d.ts +135 -6
  110. package/package.json +5 -1
  111. package/src/components/ChartJSRenderer.tsx +35 -13
  112. package/src/components/DataPreviewSection.tsx +206 -0
  113. package/src/components/MapRenderer.test.tsx +94 -5
  114. package/src/components/MapRenderer.tsx +246 -45
  115. package/src/components/ScratchpadPanel.tsx +10 -2
  116. package/src/components/VerifiedText.tsx +187 -0
  117. package/src/components/index.ts +7 -0
  118. package/src/hooks/index.ts +7 -0
  119. package/src/hooks/useDataValidator.ts +68 -0
  120. package/src/index.ts +26 -1
  121. package/src/services/data-validator.test.ts +151 -0
  122. package/src/services/data-validator.ts +149 -0
  123. package/src/services/index.ts +2 -0
  124. package/src/types/chat-bus.ts +98 -1
  125. package/src/types/index.ts +145 -6
  126. 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
  [![npm version](https://img.shields.io/npm/v/@seed-ship/mcp-ui-solid.svg)](https://www.npmjs.com/package/@seed-ship/mcp-ui-solid)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- ## What's New in v3.0.0
9
-
10
- - **18 form field types** - Added range/slider, tags/chips input, toggle switch, fieldset group. Total: text, email, password, number, date, textarea, select (multi), checkbox, radio, autocomplete (multi), range, tags, toggle, fieldset
11
- - **14 scratchpad section types** - data, filter, preview, message, action, steps, form, understanding, feedback, prompt, stepper, error, source_card, diff
12
- - **Smart field status** - `fieldStatus` (required/unsupported/unknown) + `statusReason`. Auto-exclude unsupported from submit.
13
- - **Multi-source HITL** - sectionMode append/upsert, asyncAction, pinned, debug overlay, turn state
14
- - **HITL multi-tour** - Turn state, progression stepper, understanding/feedback/prompt sections
15
- - **Interactive filter chips** - Click to edit (text or select), "+" to add filters
16
- - **Embedded forms** - FormFieldRenderer in scratchpad with depends_on reactive fields
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
- AGENT LAYER
88
- (your app logic)
89
- └──┬──────────────┬────┘
90
- events │ │ commands
91
- ▼ ▼
92
- ┌──────────────────────────────────────────────────┐
93
- Chat Messages (your app renders these)
94
- + UIResourceRenderer for MCP components
95
- ├──────────────────────────────────────────────────┤
96
- ChatPrompt (MCP-UI) choice | confirm | form
97
- ├──────────────────────────────────────────────────┤
98
- Chat Input (your app controls this)
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 (15)
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
- ```tsx
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. The agent fills sections (data, filters, preview), the human can edit filters and validate. Works for both HITL (human supervises agent) and AITL (agent supervises human/other agent).
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 { ScratchpadPanel } from '@seed-ship/mcp-ui-solid'
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
- // Listen for scratchpad SSE events
300
- bus.events.on('onScratchpad', (event) => {
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
- return (
306
- <ScratchpadPanel
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 | Renderer | Features |
345
- |------|----------|----------|
346
- | `chart` | ChartJSRenderer | Bar, line, pie, scatter, bubble, polarArea. Native Chart.js or Quickchart fallback. PNG export, configurable height. |
347
- | `table` | TableRenderer | Sortable columns, pagination, virtualization (10K+ rows). CSV/TSV/JSON export. |
348
- | `metric` | MetricRenderer | KPI cards with trends and sparklines |
349
- | `text` | TextRenderer | Markdown rendering via marked.js |
350
- | `code` | CodeBlockRenderer | Syntax highlighting (highlight.js), line numbers, word wrap toggle, filename header |
351
- | `map` | MapRenderer | Leaflet maps with markers, clustering, auto-fit bounds |
352
- | `form` | FormRenderer | Conditional fields, persistence, tool call submit |
353
- | `modal` | ModalRenderer | Portal overlay, sizes sm-full, Escape/backdrop close |
354
- | `image-gallery` | ImageGalleryRenderer | Grid layout, lightbox overlay, keyboard navigation |
355
- | `video` | VideoRenderer | YouTube/Vimeo/direct URL, auto-detect provider |
356
- | `iframe` | IframeRenderer | Tiered sandbox, 80+ whitelisted domains |
357
- | `image` | ImageRenderer | Responsive with lazy loading |
358
- | `link` | LinkRenderer | Styled link cards |
359
- | `action` | ActionRenderer | Tool call buttons |
360
- | `action-group` | ActionGroupRenderer | Grouped actions with layout options |
361
- | `grid` | GridRenderer | Nested 12-column CSS Grid |
362
- | `carousel` | CarouselRenderer | Content carousel |
363
- | `artifact` | ArtifactRenderer | File download/preview |
364
- | `footer` | FooterRenderer | Metadata display |
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, ChatPrompt, ScratchpadPanel,
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, validateIframeDomain,
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'