udi-yac 0.4.0 → 0.5.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/README.md +142 -35
- package/dist/{ce-entry-DhrrSL9F.js → ce-entry-2FSWiz2q.js} +20200 -19921
- package/dist/index.d.ts +1409 -117
- package/dist/udi-yac.css +1 -1
- package/dist/udi-yac.js +13393 -12376
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -24,14 +24,16 @@ Each is described once in [`src/app/envVars.ts`](src/app/envVars.ts); this table
|
|
|
24
24
|
|
|
25
25
|
<!-- BEGIN generated: env vars (scripts/gen-chat-env-docs.mjs) -->
|
|
26
26
|
|
|
27
|
-
| Variable | Default | Description
|
|
28
|
-
| -------------------------- | ------------------------------- |
|
|
29
|
-
| `VITE_UDI_API_BASE_URL` | `http://localhost:8007` | UDIAgent FastAPI server URL. May also be a same-origin path (e.g. `/api/yac`) when the chat sits behind the host app’s reverse proxy.
|
|
30
|
-
| `VITE_UDI_DATA_PACKAGE` | `/data/hubmap/datapackage.json` | Path or URL to a `datapackage.json`. Defaults to the bundled HuBMAP snapshot synced from `sample-data/`. Ignored when `VITE_UDI_REMOTE_PACKAGE` is set.
|
|
31
|
-
| `VITE_UDI_REMOTE_PACKAGE` | — | Name of a server-side data package (configured on the agent via `UDI_QUERY_BACKENDS`). When set, no CSVs load in the browser: metadata comes from `/v1/yac/metadata` and queries go to `/v1/yac/query`. Takes precedence over `VITE_UDI_DATA_PACKAGE`.
|
|
32
|
-
| `VITE_UDI_REQUIRE_API_KEY` | `true` | Prompt the user for an OpenAI key in the UI. Defaults to `true`, but `.env.example` ships `false` because local dev runs against an agent that has its own `OPENAI_API_KEY`.
|
|
33
|
-
| `VITE_UDI_MODEL` | — | LLM model override. Sent **only when the user supplies their own OpenAI key** — the agent honors a requested model only alongside an `X-OpenAI-Key`, so whoever pays for the tokens picks the model. Otherwise the agent’s `GPT_MODEL_NAME` applies.
|
|
34
|
-
| `
|
|
27
|
+
| Variable | Default | Description |
|
|
28
|
+
| -------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
29
|
+
| `VITE_UDI_API_BASE_URL` | `http://localhost:8007` | UDIAgent FastAPI server URL. May also be a same-origin path (e.g. `/api/yac`) when the chat sits behind the host app’s reverse proxy. |
|
|
30
|
+
| `VITE_UDI_DATA_PACKAGE` | `/data/hubmap/datapackage.json` | Path or URL to a `datapackage.json`. Defaults to the bundled HuBMAP snapshot synced from `sample-data/`. Ignored when `VITE_UDI_REMOTE_PACKAGE` is set. |
|
|
31
|
+
| `VITE_UDI_REMOTE_PACKAGE` | — | Name of a server-side data package (configured on the agent via `UDI_QUERY_BACKENDS`). When set, no CSVs load in the browser: metadata comes from `/v1/yac/metadata` and queries go to `/v1/yac/query`. Takes precedence over `VITE_UDI_DATA_PACKAGE`. |
|
|
32
|
+
| `VITE_UDI_REQUIRE_API_KEY` | `true` | Prompt the user for an OpenAI key in the UI. Defaults to `true`, but `.env.example` ships `false` because local dev runs against an agent that has its own `OPENAI_API_KEY`. |
|
|
33
|
+
| `VITE_UDI_MODEL` | — | LLM model override. Sent **only when the user supplies their own OpenAI key** — the agent honors a requested model only alongside an `X-OpenAI-Key`, so whoever pays for the tokens picks the model. Otherwise the agent’s `GPT_MODEL_NAME` applies. |
|
|
34
|
+
| `VITE_UDI_READ_ONLY` | `false` | Start in read-only mode: the chat pane and the dashboard’s top bar (counts, grid settings, session import/export, downloads) are hidden, as is every editing control on the cards, while brushing, filters and the table toggle stay. `true` leaves an Explore Data button over the dashboard that opens the chat; `locked` removes it. With the chat hidden there is nothing to build a dashboard from, so pair this with `VITE_UDI_INITIAL_SESSION`. |
|
|
35
|
+
| `VITE_UDI_INITIAL_SESSION` | — | Path or URL to a session export — the JSON written by the dashboard’s `Session → Export session` action. Fetched at startup and used to seed the dashboard and the conversation behind it. Anything under `public/` is served from the site root, so `public/demo-session.json` is `/demo-session.json`. A malformed file fails loudly through the ErrorBoundary; a missing one only logs, and the dashboard starts empty. |
|
|
36
|
+
| `VITE_BASE` | `/` | Public base path for the built SPA (read in `vite.config.ts`, build-time only). The library build always uses `./`. |
|
|
35
37
|
|
|
36
38
|
<!-- END generated: env vars -->
|
|
37
39
|
|
|
@@ -68,8 +70,8 @@ landed print the unknown token instead, so an old enough `udi-yac` shows
|
|
|
68
70
|
|
|
69
71
|
The project builds as both a **library** and a **standalone app**:
|
|
70
72
|
|
|
71
|
-
- **Library** (`pnpm build`): Exports the `UDIChat`
|
|
72
|
-
- **Standalone** (`pnpm build
|
|
73
|
+
- **Library** (`pnpm build:lib`): Exports the `UDIChat` / `UDIDashboard` components and the `UDIChatConfig` type. Consumers provide React and render `<UDIChat>` with configuration props.
|
|
74
|
+
- **Standalone** (`pnpm build`): Builds `App.tsx` as a full SPA with dev defaults.
|
|
73
75
|
|
|
74
76
|
### Library Usage
|
|
75
77
|
|
|
@@ -112,25 +114,117 @@ Embedding in another app? Two things worth knowing up front:
|
|
|
112
114
|
|
|
113
115
|
### Config Props
|
|
114
116
|
|
|
115
|
-
| Prop
|
|
116
|
-
|
|
|
117
|
-
| `apiBaseUrl`
|
|
118
|
-
| `remotePackage`
|
|
119
|
-
| `dataPackagePath`
|
|
120
|
-
| `dataPackage`
|
|
121
|
-
| `dataFieldDomains`
|
|
122
|
-
| `fetchOptions`
|
|
123
|
-
| `authToken`
|
|
124
|
-
| `requireApiKey`
|
|
125
|
-
| `model`
|
|
126
|
-
| `downloadActions`
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
117
|
+
| Prop | Type | Description |
|
|
118
|
+
| --------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
119
|
+
| `apiBaseUrl` | `string` | Base URL for the UDIAgent API. Absolute (`https://agent.example.org`) or a same-origin path (`/api/yac`). |
|
|
120
|
+
| `remotePackage` | `string?` | Server-side data package name. Schema/domains come from `GET /v1/yac/metadata` and queries from `POST /v1/yac/query`; no CSVs load in the browser and cross-filtering becomes commit-on-mouse-up. Takes precedence over both data-package props. |
|
|
121
|
+
| `dataPackagePath` | `string?` | URL/path to `datapackage_udi.json`. Ignored when `dataPackage` is provided. |
|
|
122
|
+
| `dataPackage` | `DataPackage?` | Provide a data package object directly instead of fetching from a URL. Takes precedence over `dataPackagePath`. |
|
|
123
|
+
| `dataFieldDomains` | `DataFieldDomain[]?` | Pre-computed field domains. Skips CSV loading for domain computation when provided with `dataPackage`. |
|
|
124
|
+
| `fetchOptions` | `RequestInit?` | Custom fetch options (headers, credentials, etc.) forwarded to all data-loading fetch calls. |
|
|
125
|
+
| `authToken` | `string?` | JWT bearer token for API auth. Omit it when a backend proxy attaches the header instead; no `Authorization` header is then sent. |
|
|
126
|
+
| `requireApiKey` | `boolean?` | Show API key input before chatting |
|
|
127
|
+
| `model` | `string?` | LLM model name override |
|
|
128
|
+
| `downloadActions` | `DownloadAction[]?` | Extra items appended to the Download Data dropdown. See [Custom download actions](#custom-download-actions). |
|
|
129
|
+
| `downloadButtonLabel` | `string?` | Override the Download dropdown's trigger label. Defaults to `Download Data`. |
|
|
130
|
+
| `entityIcons` | `EntityIconMap?` | Icon overrides for entity count chips. See [Custom entity icons](#custom-entity-icons). |
|
|
131
|
+
| `mascot` | `ReactNode \| null?` | Replace or hide the welcome mascot. See [Custom mascot](#custom-mascot). |
|
|
132
|
+
| `splashMessages` | `readonly string[]?` | Override or hide the randomised prompt above the mascot. See [Custom splash messages](#custom-splash-messages). |
|
|
133
|
+
| `onEvent` | `TrackerFn?` | Analytics callback invoked on key user actions. See [Analytics events](#analytics-events). |
|
|
134
|
+
| `palette` | `UDIPalette?` | Default color palette for every chart and table. See [Custom color palette](#custom-color-palette). |
|
|
135
|
+
| `readOnly` | `boolean \| 'locked'?` | Start with the chat collapsed to a rail and every editing control hidden. `'locked'` removes the way back out. See [Read-only dashboard embed](#read-only-dashboard-embed). |
|
|
136
|
+
| `initialSession` | `unknown?` | A session export to seed the dashboard and conversation with. See [Read-only dashboard embed](#read-only-dashboard-embed). |
|
|
137
|
+
| `filters` | `UDIFilter[]?` | Filters set by the embedding page. See [Filters from the host page](#filters-from-the-host-page). |
|
|
138
|
+
| `onFiltersChange` | `(filters) => void` | Called with every filter in place whenever one changes. See [Filters from the host page](#filters-from-the-host-page). |
|
|
139
|
+
| `className` | `string?` | CSS class for the root element |
|
|
140
|
+
| `style` | `CSSProperties?` | Inline styles for the root element |
|
|
141
|
+
|
|
142
|
+
### Read-only dashboard embed
|
|
143
|
+
|
|
144
|
+
To drop UDI into a host app as a **dashboard** rather than a chat, use `UDIDashboard` (or
|
|
145
|
+
`UDIChat` with `readOnly`). The chat pane, the dashboard's top bar and every editing control
|
|
146
|
+
disappear, leaving the dashboard the full width and height.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { UDIDashboard } from 'udi-yac';
|
|
150
|
+
import 'udi-yac/style.css';
|
|
151
|
+
|
|
152
|
+
<div className="h-screen">
|
|
153
|
+
<UDIDashboard
|
|
154
|
+
apiBaseUrl="/api/yac"
|
|
155
|
+
dataPackagePath="./data/hubmap/datapackage.json"
|
|
156
|
+
initialSession={savedSession}
|
|
157
|
+
/>
|
|
158
|
+
</div>;
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Read-only is the starting mode, not a lock.** A floating "Explore Data" button at the dashboard's
|
|
162
|
+
bottom right leaves read-only, at which point the full chat and every editing control appear. The
|
|
163
|
+
chat opens fresh: the conversation `initialSession` carried is hidden, though the model still has
|
|
164
|
+
it as context for the charts on the dashboard. If your users must not be able to chat at all,
|
|
165
|
+
pass `readOnly="locked"` to `UDIChat` instead: the button is dropped, leaving no way out.
|
|
166
|
+
|
|
167
|
+
| Removed in read-only | Kept in read-only |
|
|
168
|
+
| -------------------------------------------------------------------------- | --------------------------------------- |
|
|
169
|
+
| The chat pane and the data overview | Brushing and cross-filtering |
|
|
170
|
+
| Card drag, resize, rename, close, field tweak | The filter chips, including clearing |
|
|
171
|
+
| The top bar: counts, grid settings, session import / export, Download Data | The chart / table toggle and all-fields |
|
|
172
|
+
| The Filters section, while nothing is filtered | The info tooltips |
|
|
173
|
+
|
|
174
|
+
Layout changes are not written to `localStorage` while read-only, since there are none to make.
|
|
175
|
+
|
|
176
|
+
#### Seeding the dashboard
|
|
177
|
+
|
|
178
|
+
With the chat hidden there is nothing to build a dashboard from, so a read-only embed almost
|
|
179
|
+
always wants `initialSession`. It takes the JSON that the dashboard's **Session → Export session**
|
|
180
|
+
action writes — build a dashboard in the app, export it, and ship that file with your host:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import savedSession from './my-dashboard.json';
|
|
184
|
+
|
|
185
|
+
<UDIDashboard
|
|
186
|
+
apiBaseUrl="/api/yac"
|
|
187
|
+
dataPackagePath="/data/datapackage.json"
|
|
188
|
+
initialSession={savedSession}
|
|
189
|
+
/>;
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The prop is typed `unknown` so `JSON.parse(text)` can go straight in; it is validated against the
|
|
193
|
+
`SessionExport` shape and a malformed payload throws a descriptive error rather than leaving a
|
|
194
|
+
silently empty dashboard. It is applied once, after the data package finishes loading. `readOnly`
|
|
195
|
+
and `initialSession` are independent — seeding a normal, chat-enabled session works too.
|
|
196
|
+
|
|
197
|
+
To try the same thing in the standalone app without writing any code, point the two env vars at
|
|
198
|
+
an exported session — `VITE_UDI_READ_ONLY=locked` and `VITE_UDI_INITIAL_SESSION=/demo-session.json`
|
|
199
|
+
in `.env.local`, with the file dropped in `public/` (served from the site root). The app fetches it
|
|
200
|
+
at startup and hands it to `initialSession`.
|
|
201
|
+
|
|
202
|
+
### Filters from the host page
|
|
203
|
+
|
|
204
|
+
A host page can set filters and follow the ones in place, so controls outside the chat can drive it
|
|
205
|
+
and read the results it is narrowing to:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
const [filters, setFilters] = useState<UDIFilter[]>([
|
|
209
|
+
{ id: 'cohort', dataSourceKey: 'donors', type: 'point', selection: { sex: ['Female'] } },
|
|
210
|
+
]);
|
|
211
|
+
|
|
212
|
+
<UDIDashboard {...config} filters={filters} onFiltersChange={(all) => console.log(all)} />;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- **`filters`** entries are keyed by `id`. Each shows as a chip in the Filters bar and filters every
|
|
216
|
+
chart, like a filter asked for in the chat; the user can adjust, clear or remove it there. An
|
|
217
|
+
entry is applied again only when that entry changes, so re-rendering with the same array never
|
|
218
|
+
undoes the user's edits. Dropping an entry deletes its filter. Filters are applied once the data
|
|
219
|
+
package has loaded, and survive a conversation reset.
|
|
220
|
+
- **`onFiltersChange`** receives every filter in place — chat, chart and host filters, each tagged
|
|
221
|
+
with its `origin` (`'chat' | 'chart' | 'host'`). A filter whose values are empty (`[]`) has been
|
|
222
|
+
cleared: its chip stays, reading "All", and it drops nothing. Removed filters are left out.
|
|
223
|
+
Entries whose `origin` is `'chat'` or `'chart'` are ignored when passed back in `filters`, so the
|
|
224
|
+
callback's output can be fed straight back.
|
|
225
|
+
|
|
226
|
+
A `point` filter's `selection` maps each field to the values to keep; an `interval` filter's maps
|
|
227
|
+
each field to `[min, max]`.
|
|
134
228
|
|
|
135
229
|
### Data Source Configuration
|
|
136
230
|
|
|
@@ -257,7 +351,18 @@ See [`src/data/hubmapRemote.ts`](src/data/hubmapRemote.ts) for the canonical inl
|
|
|
257
351
|
|
|
258
352
|
- **Interval filters**: range sliders for numeric fields
|
|
259
353
|
- **Point filters**: checkbox selection for categorical fields
|
|
260
|
-
- **
|
|
354
|
+
- **Filters bar**: a chip per filter; each opens a popover with that filter's controls, **Clear
|
|
355
|
+
all** (keep the filter, filter nothing — the chip reads "All") and **Remove filter** (drop the
|
|
356
|
+
chip and collapse the filter's chat item; expanding that item brings it back cleared). **Reset**
|
|
357
|
+
clears every filter.
|
|
358
|
+
- **Multi-select on charts**: hold a key over a chart and click bars, their axis labels, or its legend entries:
|
|
359
|
+
- **Shift** picks a range: every category from the first click to the last, in axis or legend order.
|
|
360
|
+
- **Ctrl** (**⌘** on macOS) toggles each click on its own.
|
|
361
|
+
|
|
362
|
+
Nothing is applied (or queried) until the key is released or the pointer leaves the chart, when the picks become one filter.
|
|
363
|
+
Picks are limited to the bars drawn; to add one the chart's own filter hides, clear the
|
|
364
|
+
filter first.
|
|
365
|
+
|
|
261
366
|
- **Cross-entity filtering**: filters propagate across related entities via foreign keys
|
|
262
367
|
- **Null value filtering** toggle
|
|
263
368
|
|
|
@@ -444,6 +549,7 @@ Event names are stable, snake_case strings. **Properties carry metadata only —
|
|
|
444
549
|
| `api_key_set` | User submits a key through the `ApiKeyInput` | `inResponseToQuota: boolean` — true if a budget-exceeded rebuff had triggered the prompt (distinguishes first-time entry from quota-recovery entry) |
|
|
445
550
|
| `api_key_cleared` | User clears their stored key via the header icon | _(none)_ |
|
|
446
551
|
| `conversation_reset` | User clicks the Reset button (clears messages, pinned viz, filters, memory bank) | `conversationLength: number` — message count at the moment of reset |
|
|
552
|
+
| `read_only_exited` | User leaves read-only mode with the Explore Data button | _(none)_ |
|
|
447
553
|
| `visualization_pinned` | A new visualization is auto-pinned from an assistant response | `hasTitle: boolean`<br>`toolCallIndex: number` — position within the assistant message's tool_calls |
|
|
448
554
|
| `visualization_closed` | User clicks the × on a pinned visualization card | `hasTitle: boolean` |
|
|
449
555
|
| `download_raw_data` | User clicks "Download Raw Data" in the Download Data dropdown | `sources: number` — count of sources contributing rows<br>`rowsTotal: number` |
|
|
@@ -462,7 +568,7 @@ Every row in the table above also includes `sessionId: string`; it's omitted fro
|
|
|
462
568
|
|
|
463
569
|
**Properties you will _not_ see.** By design, the following never cross the tracker boundary: raw message text, tool_call `arguments`, OpenAI API keys, data rows, filter values. Only counts, booleans, tool-call names, ids, and short slug strings are emitted.
|
|
464
570
|
|
|
465
|
-
### Debug Mode (type
|
|
571
|
+
### Debug Mode (type `//admin` in chat)
|
|
466
572
|
|
|
467
573
|
- System prompts toggle (show/hide system messages)
|
|
468
574
|
- Conversation sidebar drawer (load saved session JSON files)
|
|
@@ -518,7 +624,10 @@ src/
|
|
|
518
624
|
DashboardPanel.tsx # Dashboard layout (counts, filters, viz grid)
|
|
519
625
|
DashboardCard.tsx # Single pinned viz (chart, toolbar, tweak, spec)
|
|
520
626
|
DataCounts.tsx # Per-entity row counts (total + filtered)
|
|
521
|
-
FilterToolbar.tsx #
|
|
627
|
+
FilterToolbar.tsx # Filter chips, each a popover of its controls
|
|
628
|
+
FilterControls.tsx # Filter widget by type + collapsible chat item
|
|
629
|
+
IntervalFilterComponent.tsx # Range slider
|
|
630
|
+
PointFilterComponent.tsx # Checkbox list
|
|
522
631
|
DownloadButton.tsx # CSV/manifest download dropdown
|
|
523
632
|
VizTweakComponent.tsx # Field encoding swap dropdowns
|
|
524
633
|
VizTweakComponent.types.ts # TweakableParam, LayerLike, MappingLike
|
|
@@ -546,9 +655,7 @@ src/
|
|
|
546
655
|
components/
|
|
547
656
|
ToolCallRenderer.tsx # Dispatches tool calls to renderers
|
|
548
657
|
VisualizationCard.tsx # UDIVis preview (chat) / pinned badge
|
|
549
|
-
FilterComponent.tsx #
|
|
550
|
-
IntervalFilterComponent.tsx
|
|
551
|
-
PointFilterComponent.tsx
|
|
658
|
+
FilterComponent.tsx # A FilterData tool call's chat item
|
|
552
659
|
FreeTextExplain.tsx # Markdown explanation with structured text
|
|
553
660
|
RebuffNotice.tsx # Rejection with suggestion buttons
|
|
554
661
|
ClarifyVariable.tsx # Field disambiguation UI
|